English 中文(简体)
Looking for a more efficient (and portable) way to obtain (numeric) file permissions in unix
原标题:

Short background: I need to monitor the permissions on a unix file (a directory) with ZABBIX to see if/when they change. ZABBIX doesn t have any built in like vfs.file.mode[xxxx] for this, so I had to roll my own UserParameter, with a numeric type.

What I do so far, is use ls -l | cut -c 2-10 to get the rwxr-xr-xpart, and then use sed to convert letters to their "weight", and awk with substr to sum it up, to get the numeric 755 or whatever value.

This is currently on Solaris, I don t have GNU coreutils stat command, and I want it to be portable and efficient, and only using standard unix tools, that are always available. (IMHO, perl is not always available).

My first attempt (example for the root directory):

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)) ) );} 

As you can see, I don t care about setuid bits or anything other than files, but purist responses are always welcome!

Surely there must be a more elegant solution. Perhaps a standard unix tool that I didn t think of.

I found this place "accidentally" about a week ago, and I really really love it! Amazing to see that much knowledge, skills, and friendliness in one place! This is my first question, so I m really excited to see if I get any response! :-) Thanks a lot!

最佳回答

I don t believe this is any more elegant/efficient than your own version but I will put it up in case any of the techniques are useful for improving your own. This could obviously be done much more simply/elegantly with a script though

The basic premise is to use tr to translate the rwx to the relevant octal numbers, then use sed to split into groups of 3 add pluses and then generate an awk command string whicg gets passed to awk to add them up.

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 -`
问题回答

if you can use find then this looks better:

find FILENAME -prune -printf %m

found it here

If your system has bash, and ls -l shows file permissions (rwxrwxrwx), you may accomplish what you were looking for with the following example:

#!/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))

The advantage is that other utilities such as awk or sed are not needed.

stat should have what you re looking for. Try one of these:

stat -c "%a" <filename>

or

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

This is long-winded, but I think it s more maintainable than yours. You can call it like this: 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
}

Implementations of ls vary, so your ls is not really portable either.

I d solve this problem using Lua, which compiles on any ANSI Standard C platform, together with the Lua POSIX library, which should build out of the box on any POSIX platform. There you can make your stat call directly and write clear simple code to do the arithmetic. An excellent introduction to Lua Programming in Lua is available free online (for the previous version of Lua). Finally, if you care about efficiency, the results will be extremely efficient, partly because Lua is fast, but mostly because you will be able to do everything while forking only one process—the Lua interpreter.





相关问题
KornShell- Creating a fixed width text file

I need to create a simple fixed width text file in KornShell (ksh). My current attempt using printf to pad the string isn t working out very well. What s the shortest, cleanest way to create a fixed ...

unix find command

how to use the find command to find files/directories which are not matching the pattern. for eg: find <some options > -name "dontfile.txt" should give me output of all the find whose file ...

encoding of file shell script

How can I check the file encoding in a shell script? I need to know if a file is encoded in utf-8 or iso-8859-1. Thanks

Case insensitive comparison of strings in shell script

The == operator is used to compare two strings in shell script. However, I want to compare two strings ignoring case, how can it be done? Is there any standard command for this?

1. 露台式照像

在Windows XP中,没有一时出现指挥时,是否有办法操作一种灰色文字? 我常常需要把“善待”(工作)与“灰色”同起来,即使我的文字没有产出,......

热门标签