Macos – Making ls aware of “hidden” file flag

lsmacosterminal.app

Is it possible to make ls aware of the hidden file flag on Mac OS X?

Currently, a simple ls -lO produces:

$ ls -lO
total 0
drwxr-xr-x@  84 danielbeck  staff  -      2856 29 Mai 22:44 Applications
drwx------+ 158 danielbeck  staff  -      5372 29 Mai 15:27 Desktop
drwx------@ 250 danielbeck  staff  -      8500 30 Mai 20:40 Documents
drwx------+  11 danielbeck  staff  -       374 29 Mai 22:21 Downloads
drwx------@  84 danielbeck  staff  -      2856 29 Mai 22:48 Library
drwx------@   3 danielbeck  staff  hidden  102  3 Apr 20:45 Movies
drwx------@   5 danielbeck  staff  hidden  170  3 Apr 20:45 Music
drwx------+ 215 danielbeck  staff  -      7310 29 Mai 22:54 Pictures
drwxr-x---@   7 danielbeck  staff  hidden  238  3 Apr 20:45 Public
drwxr-xr-x@   4 danielbeck  staff  hidden  136 24 Apr 23:25 Sites

So we have three kinds of visibility: regular, visible files, files with the hidden file flag, that aren't actually hidden in Terminal, and really hidden files whose names start with a dot.

Is there a way, e.g. using an alias or a reliable shell function, to make ls treat hidden flagged and .dothidden files the same, i.e. hide by default and show with ls -A or ls -a, similar to how Finder behaves depending on the value of defaults read com.apple.Finder AppleShowAllFiles?

I am aware that man chflags specifically mentions hidden flag only hides from GUI, i.e. Finder.

Best Answer

These are the steps to get an OS X ls which hides files with the hidden flag unless the -a/-A option is specified, similar to dot files.

  1. Install Xcode. I am using Xcode 4.5.1 below.
  2. Download your OS release's libutil and file_cmds from http://www.opensource.apple.com. There's a download button on the right side of each package list entry. This guide was written for OS X 10.8.2, YMMV with the exact steps below if you're on a different version.
  3. Extract both archives.
  4. Open the file_cmds.xcodeproj in Xcode and select to build the ls target.

    Screenshot

  5. Select the file_cmds Xcode project on the left, and select the ls target in the main area. In the Build Settings tab, look for Header Search Paths in the Headers category and add the path to the folder to where you extracted libutil.

    Screenshot

  6. Open the file print.c in the ls folder on the left, and remove the line that says #include <membershipPriv.h>. Save the file afterwards. This should break something, because includes are there for a reason, but I haven't yet determined what it is.

  7. Open the file ls.c in the same folder, and look for a comment saying /* Only display dot file if -a/-A set. */ in the display function. Replace it and the condition below it with the following:

    /* Only display dot file and file with hidden flag if -a/-A set. */
    sp = cur->fts_statp;
    if (((sp != NULL && (sp->st_flags & 0x8000)) || cur->fts_name[0] == '.') && !f_listdot) {
        cur->fts_number = NO_PRINT;
        continue;
    }
    
  8. Press Cmd-B to build.

    Success!

  9. Select Products on the left (end of the folder list) and right-click ls. Select Show in Finder.

    Build Output folder screenshot

  10. Move the ls executable somewhere convenient, e.g. your home directory. Then open Terminal and run sudo mv $HOME/ls /bin/ls, or, even better, create a new folder named bin in your home directory and move it there. Add that folder to your PATH afterwards.

Testing the result:

$ mkdir test
$ cd test
$ touch foo bar
$ chflags hidden bar
$ /bin/ls -lO
total 0
-rw-r--r--@ 1 danielbeck  staff  hidden 0 25 Okt 22:25 bar
-rw-r--r--  1 danielbeck  staff  -      0 25 Okt 22:25 foo
$ $HOME/bin/ls -lO
total 0
-rw-r--r--  1 danielbeck  staff  - 0 25 Okt 22:25 foo
$ $HOME/bin/ls -A
bar foo