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

时间:2017-04-14 20:53:59

标签: ruby unix file-permissions

我已阅读another answer了解如何使用perl获取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类和#printf方法。但是,我的所有输出都是领先的。

$ 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脚本相同的输出?

3 个答案:

答案 0 :(得分:9)

如果您查看libc手册的第二部分(shell中的Enumerable.Where),您会看到如下内容:

  

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

man 2 stat

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

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

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

这就是您的领导#define S_IFREG 0100000 /* regular */ 的来源。

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

100

只获取权限位。如果你在Ruby中做同样的事情:

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

你会得到你期望的那种输出。

如果您没有libc手册页,那么您可以查看OpenGroup's stat documentation,它将指向struct stat documentation,其中涵盖模式中的各个位:

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

答案 1 :(得分:2)

  

在macOS机器上给出的100分是什么意思?

File::Stat#mode方法的返回值取决于平台,显然是它在您的平台上返回的内容。

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

  

状态信息字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 */

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

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

  • 常规文件,而不是fifo,字符设备,目录,块设备,符号链接,套接字或白名
  • 不是suid
  • not sgid
  • 不粘
  • 可读且可写,但不能由其所有者执行
  • 可读,但不可写或可由群组执行
  • 可读,但不可写或其他人可执行
  

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

%04o表示"格式为八进制,最小长度为4,如果长度小于4&#34,则填充零。而这正是它的作用。

  

如何实现与链接的perl脚本相同的输出?

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

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

答案 2 :(得分:0)

应该如此简单:

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