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

3

我阅读了关于如何使用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

到目前为止,我已经使用了File::Stat类和#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
  • 如果我在macOS机器上,前面的100是什么意思?
  • 为什么我的"%04o"无法正常工作?
  • 如何实现与链接perl脚本相同的输出?

1
那只是File::Stat#mode方法的返回值,文档中的示例完全相同。 - Jörg W Mittag
但是为什么有100呢? - mbigras
因为这就是File::Stat#mode返回的内容,正如文档所述。正如文档所说,File::Stat#mode的返回值取决于平台,在您的平台上,显然它返回了这个值。 - Jörg W Mittag
你的机器上这个 Ruby 单行代码会返回什么? - mbigras
3个回答

10

如果您查看libc手册的第二部分(通过shell输入 man 2 stat ),您应该会看到类似于以下内容:

状态信息字st_mode具有以下位:

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

具体内容可能不完全相同,但在任何Unix系统中八进制值应该是相同的。

你感兴趣的部分是“这是一个常规文件”的位:

#define S_IFREG  0100000  /* regular */

这就是你的前导 100 来源所在。

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

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

要获取权限位,如果你在Ruby中进行相同的操作:

printf "%04o\t#{f}\n", (File.stat(f).mode & 07777)
# ----------------------------------------^^^^^^^

你会得到你期望的输出类型。


如果你没有libc man页面,那么你可以查看OpenGroup的stat文档,它将指向struct stat文档,该文档涵盖模式中的各种位。

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

3
这应该很简单:
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

split("")join不是必需的。 - steenslag
实际上,也不需要 to_i(8),您可以直接与 "0755" 进行比较。我将 splitjoin 留给任何想单独使用这些代码的人(就像我一样)。 - ribamar

2
如果我正在使用 macOS 机器,那么“leading 100”是什么意思? File::Stat#mode 方法的返回值与平台有关,显然在您的平台上它返回这个值。
特别地,文档说明对于 Unix 平台,使用的定义来自 stat(2),在 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规范中的描述相符,因此它对于所有Unix系统而言都是或多或少正确的,而不仅仅是macOS。(macOS还有额外的“whiteout”文件类型,与Time Machine有关,据我所知,但没关系,SUS允许额外的文件类型和权限位。)
因此,如果我理解正确,这意味着hello_world.rb是:
  • 一个普通文件,不是FIFO、字符设备、目录、块设备、符号链接、套接字或白出文件
  • 没有SUID权限
  • 没有SGID权限
  • 没有粘滞位
  • 可读写,但由其所有者不可执行
  • 可读取,但由组不可写入或执行
  • 可读取,但由其他人不可写入或执行

为什么我的"%04o"不能用?

"%04o"的意思是“以八进制格式输出,最小长度为4,如果长度小于4,则用零填充”。这正是它所做的。
“我如何实现与链接的perl脚本相同的输出?” 如果您想获得相同的输出,则应该做同样的事情:Perl脚本从模式中屏蔽文件类型,如果您在Ruby中执行相同的操作,则应该获得相同的结果。
Dir["**/**"].each { |f| printf "%04o\t#{f}\n", File.stat(f).mode & 07777 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接