Joe Caruso
Joe Caruso

Reputation: 1394

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

Upvotes: 0

Views: 1454

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 755026

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.

Upvotes: 2

Related Questions