如何使用 Ruby 获得八进制文件权限?

How can I get octal file permissions with Ruby?

我使用 perl 阅读 another answer for how to get the octal file permissions

$ 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

到目前为止,我使用的是 File::Stat class and the #printf 方法。但是,我的所有输出都获得前导 100。

$ 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

如果您查看 libc 手册的第二部分(shell 中的man 2 stat),您应该会看到如下内容:

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 */

确切的内容不会完全相同,但八进制值在任何 Unixy 系统上都应该相同。

您感兴趣的部分是 "this is a regular file" 位:

#define S_IFREG  0100000  /* regular */

这就是您的前导 100 的来源。

如果您回顾一下 Perl 版本,您会发现他们正在应用位掩码:

(stat)[2] & 07777
          ^^^^^^^

只获取权限位。如果你在 Ruby:

中做同样的事情
printf "%04o\t#{f}\n", (File.stat(f).mode & 07777)
# ----------------------------------------^^^^^^^

您将获得您期望的那种输出。


如果您没有 libc 手册页,那么您可以查看 OpenGroup's stat documentation which will point you at the struct stat documentation,其中涵盖了模式中的各个位:

┌─────────┬───────────┬───────────────────────────────────────────┐
│ 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. │
└─────────┴───────────┴───────────────────────────────────────────┘

What does the leading 100 mean given I'm on a macOS machine?

File::Stat#mode 方法的 return 值取决于平台,显然,这就是它在您的平台上 return 的值。

特别是,文档说对于 Unix 机器,使用 stat(2) 中的定义,on macOS 如下:

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 */

这与 Single Unix Specification 中的描述相符,因此它或多或少适用于 所有 Unices,而不仅仅是 macOS。 (macOS 有额外的 "whiteout" 文件类型,这与 Time Machine 相关,AFAIK,但没关系,SUS 允许额外的文件类型和权限位。)

所以,如果我解读正确,那就意味着 hello_world.rb

  • 常规文件,不是 fifo、字符设备、目录、块设备、符号链接、套接字或 whiteout
  • 不适应
  • 不是 sgid
  • 不粘
  • 可读可写,但不能被其所有者执行
  • 组可读,但不可写或可执行
  • 其他人可读,但不可写或可执行

Why does my "%04o" not work?

%04o 表示 "format as octal, minimum length 4, pad with zeroes if length is less than 4"。这正是它的作用。

How do I achieve the same output as the linked perl script?

如果你想获得相同的输出,你应该做同样的事情:Perl 脚本从模式中屏蔽掉文件类型,如果你在 Ruby 中做同样的事情,你应该得到相同的结果结果:

Dir["**/**"].each { |f| printf "%04o\t#{f}\n", File.stat(f).mode & 07777 }

它应该很简单:

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