Reputation: 8055
I read another answer for how to get the octal file permissions using perl:
$ perl -e 'printf "%04o %s\n", (stat)[2] & 07777, $_ for @ARGV' *.txt
0644 1.txt
0644 2.txt
0644 3.txt
0644 4.txt
0600 PerlOneLiner.txt
0664 perl.txt
So far I've used the File::Stat
class and the #printf
method. However, I'm getting a leading 100 on all my output.
$ ruby -e 'Dir["**/**"].each { |f| printf "%04o\t#{f}\n", File.stat(f).mode }'
100711 cplink
100644 hello_world.rb
100755 lso
100711 rename_images
"%04o"
not work?Upvotes: 3
Views: 3040
Reputation: 1495
It should be as simple as:
path = "file_with_0755"
File.stat(path).mode.to_s(8).split("")[-4..-1].join
# => "0755"
File.stat(path).mode.to_s(8).split("")[-4..-1].join.to_i(8) == 0755
# => true
Upvotes: 3
Reputation: 434945
If you check section two of your libc manual (man 2 stat
from the shell) you should see something like this:
The status information word st_mode has the following bits:
#define S_IFMT 0170000 /* type of file */ #define S_IFIFO 0010000 /* named pipe (fifo) */ #define S_IFCHR 0020000 /* character special */ #define S_IFDIR 0040000 /* directory */ #define S_IFBLK 0060000 /* block special */ #define S_IFREG 0100000 /* regular */ #define S_IFLNK 0120000 /* symbolic link */ #define S_IFSOCK 0140000 /* socket */ #define S_IFWHT 0160000 /* whiteout */ #define S_ISUID 0004000 /* set user id on execution */ #define S_ISGID 0002000 /* set group id on execution */ #define S_ISVTX 0001000 /* save swapped text even after use */ #define S_IRUSR 0000400 /* read permission, owner */ #define S_IWUSR 0000200 /* write permission, owner */ #define S_IXUSR 0000100 /* execute/search permission, owner */
The precise contents won't be exactly the same but the octal values should be the same on any Unixy system.
The part you're interested in would be the "this is a regular file" bit:
#define S_IFREG 0100000 /* regular */
That's where your leading 100
comes from.
If you look back at the Perl version, you'll see that they're applying a bit mask:
(stat)[2] & 07777
^^^^^^^
to grab just the permission bits. If you do the same in Ruby:
printf "%04o\t#{f}\n", (File.stat(f).mode & 07777)
# ----------------------------------------^^^^^^^
you'll get the sort of output that you're expecting.
If you don't have libc man pages then you can look at the OpenGroup's stat
documentation which will point you at the struct stat
documentation which covers the various bits in the mode:
┌─────────┬───────────┬───────────────────────────────────────────┐
│ Name │ Numeric │ Description │
│ │ Value │ │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_IRWXU │ 0700 │ Read, write, execute/search by owner. │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_IRUSR │ 0400 │ Read permission, owner. │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_IWUSR │ 0200 │ Write permission, owner. │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_IXUSR │ 0100 │ Execute/search permission, owner. │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_IRWXG │ 070 │ Read, write, execute/search by group. │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_IRGRP │ 040 │ Read permission, group. │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_IWGRP │ 020 │ Write permission, group. │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_IXGRP │ 010 │ Execute/search permission, group. │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_IRWXO │ 07 │ Read, write, execute/search by others. │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_IROTH │ 04 │ Read permission, others. │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_IWOTH │ 02 │ Write permission, others. │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_IXOTH │ 01 │ Execute/search permission, others. │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_ISUID │ 04000 │ Set-user-ID on execution. │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_ISGID │ 02000 │ Set-group-ID on execution. │
├─────────┼───────────┼───────────────────────────────────────────┤
│ S_ISVTX │ 01000 │ On directories, restricted deletion flag. │
└─────────┴───────────┴───────────────────────────────────────────┘
Upvotes: 10
Reputation: 369594
What does the leading 100 mean given I'm on a macOS machine?
The return value of the File::Stat#mode
method is platform-dependent, and apparently, that's what it returns on your platform.
In particular, the documentation says that for Unix machines, the definition from stat(2)
is used, which on macOS is the following:
The status information word st_mode has the following bits:
#define S_IFMT 0170000 /* type of file */ #define S_IFIFO 0010000 /* named pipe (fifo) */ #define S_IFCHR 0020000 /* character special */ #define S_IFDIR 0040000 /* directory */ #define S_IFBLK 0060000 /* block special */ #define S_IFREG 0100000 /* regular */ #define S_IFLNK 0120000 /* symbolic link */ #define S_IFSOCK 0140000 /* socket */ #define S_IFWHT 0160000 /* whiteout */ #define S_ISUID 0004000 /* set user id on execution */ #define S_ISGID 0002000 /* set group id on execution */ #define S_ISVTX 0001000 /* save swapped text even after use */ #define S_IRUSR 0000400 /* read permission, owner */ #define S_IWUSR 0000200 /* write permission, owner */ #define S_IXUSR 0000100 /* execute/search permission, owner */
This matches up with the description in the Single Unix Specification, so it is more or less true for all Unices, not just macOS. (macOS has the additional "whiteout" file type, which is related to Time Machine, AFAIK, but that's okay, the SUS allows additional file types and permission bits.)
So, if I decipher that correctly, it means that hello_world.rb
is
Why does my
"%04o"
not work?
%04o
means "format as octal, minimum length 4, pad with zeroes if length is less than 4". And that's exactly what it does.
How do I achieve the same output as the linked perl script?
If you want to get the same output, you should do the same thing: the Perl script masks out the file type from the mode, if you do the same in Ruby, you should get the same result:
Dir["**/**"].each { |f| printf "%04o\t#{f}\n", File.stat(f).mode & 07777 }
Upvotes: 2