12

I know you can set or unset the hidden flag of a folder/file by doing chflags hidden foo.txt and chflags nohidden foo.txt.

But is there anyway of telling whether the folder/file is currently hidden or not?

I don't want to just determine if the folder/file is beginning with a dot.

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
Tyilo
  • 5,891
  • 12
  • 47
  • 61

3 Answers3

12

According to the ls man page, you should be able -O option combined with the -l option to view flags with ls. For example:

ls -Ol foo.txt
-rw-r--r-- 1 harry staff - 0 18 Aug 19:11 foo.txt
chflags hidden foo.txt
ls -Ol foo.txt
-rw-r--r-- 1 harry staff hidden 0 18 Aug 19:11 foo.txt
chflags nohidden foo.txt
ls -Ol foo.txt
-rw-r--r-- 1 harry staff - 0 18 Aug 19:11 foo.txt

Edit: Just to give a more specific solution to what the OP wanted (see comments below): To see if a folder is hidden or not, we can pass the -a option to ls to view the folder itself. We can then pipe the output into sed -n 2p (thanks Stack Overflow) to get the required line of that output. An example:

mkdir foo
chflags hidden foo
ls -aOl foo | sed -n 2p
drwxr-xr-x@ 2 harry staff hidden 68 18 Aug 19:11 .

Edit 2: For a command that should work regardless of whether it's a file or a folder, we need to do something slightly more hacky.

The needed line of output from ls -al varies depending on whether the thing is a file or folder, as folders show a total count, whereas files do not. To get around this, we can grep for the character r. This should be in ~all of all files/folders (nearly all should have at least one read permission), but not in the totals line.

As the line we want to get then becomes the first line, we can use head -n 1 to get the first line (alternative, if you prefer sed, sed -n 1p could be used).

So, for example with a directory:

mkdir foo
chflags hidden foo
ls -aOl foo | grep r | head -n 1
drwxr-xr-x@ 2 harry staff hidden 68 18 Aug 19:11 .

and with a file:

touch foo.txt
chflags hidden foo.txt
ls -aOl foo.txt | grep r | head -n 1
-rw-r--r-- 1 harry staff hidden 0 18 Aug 19:11 foo.txt

Edit 3: See Tyilo's answer below for a nicer way than grepping for r :)

hrickards
  • 236
  • 2
  • 4
  • But doing this with a folder, will list the flags for the files/folders under it – Tyilo Aug 18 '11 at 18:18
  • To just view hidden files, pipe it through grep (e.g `ls -Ol fooDir/ | grep hidden`) to view only hidden files/folders. This will still show all the files, but if you pipe it through some sed/awk magic (someone else will have to help here I'm afraid) you should be able to get just a list of files. –  Aug 18 '11 at 18:22
  • I don't want a list of the files I just want to know is folder "foo" is hidden or not – Tyilo Aug 18 '11 at 18:27
  • Ok. So to view the directory itself add the `-a` option to ls. To just get the line you need from the output, you can use sed. For example: `ls -aOl foo | sed -n 2p`. This will display one line of output. If it contains the word "hidden", then foo is hidden. If it does not, foo is not hidden. :) –  Aug 18 '11 at 18:33
  • But what if I want to get if it's hidden, when I don't know if it's a file or folder. Is that possible to do in one line without using test or [[? – Tyilo Aug 18 '11 at 18:40
  • The `-a` switch will work regardless of whether it's a file or folder. However, the result you want will then be on the first line, not the second. The solution I've come up with, although it's a bit hacky will only show lines including the 'r' character - not the total line at the top of `ls -al` for a directory. This does assume your file/folder has read permissions for someone, but I think that's pretty safe to assume :). So the solution is: `ls -aOl foo | grep r | head -n 1`. Should work regardless of whether foo is a file or folder. –  Aug 18 '11 at 18:47
  • 2
    Using `ls -Old dirname/` will show you the properties of the directory itself, not its contents. – bahamat Aug 18 '11 at 23:10
  • On 10.9.x (Mavericks), `ls -lOd ~/Library` (uppercase "O") gives **ls: invalid option -- 'O'**. `man ls` does not show uppercase "O" as an option (so I can see why it returns **invalid option** HOWEVER `man chflags` does clearly state, **You can use "ls -lO" to see the flags of existing files.** (uppercase "O"). In summary, `man chflags` says to use uppercase "O" with `ls` but `ls` absolutely doesn't support it. – Setaa Jan 24 '21 at 22:33
7

Found the solution here: How can I make ls show information about the directory specified only, not info about its sub-files or folder contents?

Which basically is ls -ldO foo and then you just append | awk '{ print $5 }' to make it display the information.

Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
Tyilo
  • 5,891
  • 12
  • 47
  • 61
  • 1
    Be aware that the awk will break if there is whitespace in the username or groupname (which should be extremely unlikely, but hey). I added a safer solution that uses `stat`. – mrm Apr 17 '18 at 17:29
2

As referenced by @Tyilo, @Sorpigal suggests trying stat, which encodes "user flags" with %Xf (heX encoded user flag), and is much safer for machine parsing.

$ stat -f "%Xf" ~/Library
8000

The hex values for user flags live here: grep UF /usr/include/sys/stat.h. As of macOS 10.11:

#define UF_SETTABLE     0x0000ffff  /* mask of owner changeable flags */
#define UF_NODUMP       0x00000001  /* do not dump file */
#define UF_IMMUTABLE    0x00000002  /* file may not be changed */
#define UF_APPEND       0x00000004  /* writes to file may only append */
#define UF_OPAQUE       0x00000008  /* directory is opaque wrt. union */
/* #define UF_NOUNLINK  0x00000010 */   /* file may not be removed or renamed */
#define UF_COMPRESSED   0x00000020  /* file is hfs-compressed */
/* UF_TRACKED is used for dealing with document IDs.  We no longer issue
   notifications for deletes or renames for files which have UF_TRACKED set. */
#define UF_TRACKED      0x00000040
#define UF_HIDDEN       0x00008000  /* hint that this item should not be */
mrm
  • 121
  • 3
  • 1
    On 10.15.x I didn't have `/usr/include` but with Xcode11 + CLT, I was able to use `grep UF /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/stat.h` – luckman212 May 26 '20 at 21:29
  • On 10.9.x (Mavericks), `stat -f "%Xf" ~/Library` gives **stat: cannot read file system information for '%Xf': No such file or directory** plus several more lines of `stat` info, none of which shows `8000`. In looking at `man stat` I thought maybe the error is due to the lack of `-c` to indicate output format, but `stat -f -c "%Xf" ~/Library` gives the one line output of `?f` which I'm interpreting (probably incorrectly) that the output of `?` indicates it doesn't know how to deal with `%X` and the output of `f` is just the literal `f` (meaning, `f` has no special meaning for `-c`). – Setaa Jan 24 '21 at 22:53
  • 1
    @Setaa you may be using the wrong stat. You want `/usr/bin/stat` (the one from macOS, not from homebrew) – mrm Jan 28 '21 at 07:06
  • @mrm -- you're right. I'm using the wrong stat but didn't realize it so thanks for your reply. `/usr/bin/stat -f "%Xf" ~/Library` works perfectly. I was using the one from Macports (since homebrew isn't supported on 10.9 anymore), which is GNU stat version 8.32 circa 2020. If I do `strings /usr/bin/stat|head -1` it reports version 1.6 circa 2003. – Setaa Jan 30 '21 at 22:02