寻找一种更有效(和可移植)的方式在 unix 中获取(数字)文件权限

Posted

技术标签:

【中文标题】寻找一种更有效(和可移植)的方式在 unix 中获取(数字)文件权限【英文标题】:Looking for a more efficient (and portable) way to obtain (numeric) file permissions in unix 【发布时间】:2011-03-12 20:44:27 【问题描述】:

简短背景:我需要使用 ZABBIX 监控 unix 文件(目录)的权限,以查看它们是否/何时更改。 ZABBIX 没有像 vfs.file.mode[xxxx] 这样的内置函数,所以我不得不滚动我自己的 UserParameter,使用数字类型。

到目前为止,我所做的是使用ls -l | cut -c 2-10 获取rwxr-xr-xpart,然后使用sed 将字母转换为它们的“重量”,然后使用awksubstr 进行总结,获取数字 755 或任何值。

这目前在 Solaris 上,我没有 GNU coreutils stat 命令,我希望它具有可移植性和高效性,并且只使用始终可用的标准 unix 工具。 (恕我直言,perl 并不总是可用)。

我的第一次尝试(以根目录为例):

ls -ld / | \
cut -c 2-10 | \
sed -e 's%-%0%g' -e 's%r%4%g' -e 's%w%2%g' -e 's%x%1%g' | \
awk 'print (100 * ((substr($0,1,1)) + (substr($0,2,1)) + (substr($0,3,1))) + \
     (10 * ((substr($0,4,1) + (substr($0,5,1)) + (substr($0,6,1)) ))) + \
     ( (substr($0,7,1)) + (substr($0,8,1)) + (substr($0,9,1)) ) );'

如您所见,我不关心 setuid 位或文件以外的任何内容,但始终欢迎纯粹的回应!

肯定有更优雅的解决方案。也许是我没想到的标准 unix 工具。

大约一周前,我“偶然”发现了这个地方,我真的很喜欢它!在一个地方看到这么多知识、技能和友善,真是太棒了! 这是我的第一个问题,所以我很高兴看到我是否得到任何回应! :-) 非常感谢!

【问题讨论】:

您正在寻找的内容可以通过系统调用轻松获得。没有必要重新发明***,除了“好玩”。 问题是编写我自己的stat(2) 包装器实际上正在重新发明***。我需要一些可以放入配置文件的东西,而无需在被监控的主机上安装额外的程序。 【参考方案1】:

如果你可以使用find 那么这看起来更好:

find FILENAME -prune -printf '%m\n'

找到它here

【讨论】:

【参考方案2】:

我不认为这比您自己的版本更优雅/高效,但我会提出它,以防任何技术对改进您自己的技术有用。这显然可以通过脚本更简单/优雅地完成

基本前提是使用 tr 将 rwx 转换为相关的八进制数,然后使用 sed 将 3 个加号分成一组,然后生成一个 awk 命令字符串,将其传递给 awk 以将它们相加。

ls -ld / | \
cut -c2-10 | \
tr 'rwx-t' '42100' | \
sed -E -e 's/(...)(...)(...)/\1 \2 \3/g' \
-e 's/([0-9])([0-9])([0-9])/\1+\2+\3/g' \
-e 's/^(.*)$/BEGIN print \1/g'|\
awk -f -`

【讨论】:

我的tr 抱怨连字符,除非我逃脱了它。您的第一个和第三个g 不是必需的。这是您的 GNU sed 版本,它大大简化了。它可以很容易地转换回-e 形式。 ls -ld / cur -c2-10 | tr 'rwx\-t' '42100' | sed -r 's/(...)/\1 /g;s/([0-9])/\1+0/g;s/.*/BEGIN print &/' | awk -f - 当我使用tr 或编写正则表达式时,我总是将连字符放在最后。当然tr 比我最初的sed 更优雅,因为它做同样的事情。谢谢,史蒂夫!我看看能不能用bcexpr 代替awk。【参考方案3】:

如果您的系统有bash,并且ls -l 显示文件权限 (rwxrwxrwx),您可以通过以下示例完成您所寻找的:

#!/bin/sh
[ ! -d $1 ] && echo "Error: "$1" is not a directory" && exit 1 
set -- `ls -ld $1`;P=$1:1:9;P=$P//r/4 ;P=$P//w/2 ;P=$P//x/1 ;P=$P//-/0 
set -- $P; echo $((($1+$2)+$3))$((($4+$5)+$6))$((($7+$8)+$9))

优点是不需要其他实用程序,例如 awk 或 sed。

【讨论】:

【参考方案4】:

stat 应该有你要找的东西。尝试以下方法之一:

stat -c "%a" <filename>

stat --printf="%a" <filename>

【讨论】:

并非所有 unice 都带有 stat 命令。这就是为什么我写了我不想使用它。 啊,废话。我错过了你帖子中的那个注释。对不起:^) stat 命令行工具可能没有,但所有 Unix 发行版都有这样的系统调用。【参考方案5】:

这是冗长的,但我认为它比你的更易于维护。你可以这样称呼它:ls -ld / | cut -c 2-10 | ./perm.awk

#!/usr/bin/gawk -f
# OR: #!/usr/bin/nawk -f

function conv(num, len, i, val) 
    # converts binary string to decimal (or octal if fed 3 "bits" at a time)
    # call with num as argument, others are local variables
    len = length(num)
    for(i = len; i > 0; i--) 
        if (substr(num, i, 1) == 1) 
            val = val + 2 ^ (len - i)
        
    
    return val


# main loop

    # TODO: handle [sStT]
    gsub("[rwx]", 1)    # make it look binary
    gsub("-", 0)
    for(i = 0; i < 3; i++) 
        perm = perm conv(substr($0, i * 3 + 1, 3))    # convert the "bits" 3 at a time
    


END 
    print perm

【讨论】:

不错。谢谢!不过,我现在正在寻找不需要任何额外安装/文件的东西。【参考方案6】:

ls 的实现各不相同,因此您的 ls 也不是真正可移植的。

我会使用Lua 解决这个问题,它可以在任何ANSI 标准C 平台上编译,以及Lua POSIX library,它应该在任何POSIX 平台上开箱即用。在那里,您可以直接调用stat 并编写清晰的简单代码来进行算术运算。 Lua Programming in Lua 的精彩介绍可在线免费获得(适用于 Lua 的早期版本)。最后,如果您关心效率,那么结果将非常高效,部分原因是 Lua 速度很快,但主要是因为您将能够在仅派生一个进程(即 Lua 解释器)的同时完成所有工作。 p>

【讨论】:

Lua 看起来很有趣。我一定会调查它(其他事情)。

以上是关于寻找一种更有效(和可移植)的方式在 unix 中获取(数字)文件权限的主要内容,如果未能解决你的问题,请参考以下文章

Python - 寻找一种更有效的方法来重新编写字典中的键

寻找一种更 Pythonic 的方式将一个充满字典的列表合并为一个?

如何以有效的方式同步列表和可枚举?

为啥一种方法比另一种更有效?

寻找一种有效的迭代方式

一种更有效的方法来总结 postgres 中列之间的差异?