Search code examples
bashpermissionsoctal

Working with octal permissions in bash


How do I get the masked (user) permissions from that permissions octal value?

Output should look like:

testfile1:
Permissions: 644
Masked Permissions: 600
testfile2:
Permissions: 750
Masked Permissions: 700

All I have now is:

for file in $@
do
    value=$(stat --printf '%a' $file)
    echo "permissions: $value"

    maskedvalue= # ???
    echo "permissions, masked: $maskedvalue"

done

Solution

  • Given that it is bash, you can do:

     printf "%.4o\n" $(( $(stat -f '0%Lp' "$file") & ~$(umask) ))
    

    at least, on Mac OS X, where stat -f '%Lp' means 'print the user, group, other permissions in octal'. If you're on Linux, you'll need to translate that to the GNU stat syntax, which looks like it probably is:

    printf "%.4o\n" $(( $(stat --printf '%a' "$file") & ~$(umask) ))
    

    The spaces after $(( and before )) are not strictly needed in the sense that the shell knows what to do even if they are missing; likewise the spaces around the &. OTOH, if anyone else has to read the code, you probably want those spaces there.


    Test code:

    file="./mode-file"
    trap "rm -f $file; exit 1" 0 1 2 3 13 15
    
    cp /dev/null "$file"
    
    for mode in 777 755 644 640 444 440 400
    do
        chmod $mode $file
        ls -l $file
        for umask in 002 022 027 033 037 077 177
        do
            umask $umask
            printf "$mode & ~$umask = %.4o\n" $(( $(stat -f '0%Lp' "$file") & ~$(umask) ))
        done
    done
    
    rm -f $file
    trap 0
    

    Example output:

    -rwxrwxrwx  1 jleffler  staff  0 Nov 11 20:57 ./mode-file
    777 & ~002 = 0775
    777 & ~022 = 0755
    777 & ~027 = 0750
    777 & ~033 = 0744
    777 & ~037 = 0740
    777 & ~077 = 0700
    777 & ~177 = 0600
    -rwxr-xr-x  1 jleffler  staff  0 Nov 11 20:57 ./mode-file
    755 & ~002 = 0755
    755 & ~022 = 0755
    755 & ~027 = 0750
    755 & ~033 = 0744
    755 & ~037 = 0740
    755 & ~077 = 0700
    755 & ~177 = 0600
    -rw-r--r--  1 jleffler  staff  0 Nov 11 20:57 ./mode-file
    644 & ~002 = 0644
    644 & ~022 = 0644
    644 & ~027 = 0640
    644 & ~033 = 0644
    644 & ~037 = 0640
    644 & ~077 = 0600
    644 & ~177 = 0600
    -rw-r-----  1 jleffler  staff  0 Nov 11 20:57 ./mode-file
    640 & ~002 = 0640
    640 & ~022 = 0640
    640 & ~027 = 0640
    640 & ~033 = 0640
    640 & ~037 = 0640
    640 & ~077 = 0600
    640 & ~177 = 0600
    -r--r--r--  1 jleffler  staff  0 Nov 11 20:57 ./mode-file
    444 & ~002 = 0444
    444 & ~022 = 0444
    444 & ~027 = 0440
    444 & ~033 = 0444
    444 & ~037 = 0440
    444 & ~077 = 0400
    444 & ~177 = 0400
    -r--r-----  1 jleffler  staff  0 Nov 11 20:57 ./mode-file
    440 & ~002 = 0440
    440 & ~022 = 0440
    440 & ~027 = 0440
    440 & ~033 = 0440
    440 & ~037 = 0440
    440 & ~077 = 0400
    440 & ~177 = 0400
    -r--------  1 jleffler  staff  0 Nov 11 20:57 ./mode-file
    400 & ~002 = 0400
    400 & ~022 = 0400
    400 & ~027 = 0400
    400 & ~033 = 0400
    400 & ~037 = 0400
    400 & ~077 = 0400
    400 & ~177 = 0400
    

    NB: Tested on Mac OS X 10.9 (Mavericks). If you are using a GNU/Linux platform, you must change the stat command to use the notation that works on your machine.