4

I need to get Access rights in more human readable format for file or folder with a symbolic notation like this u=rwx,g=srwx,o-rwx (possibly sticky bits)

  • Using stat --format '%a', I obtain a result with format 2770, octal format
  • Using stat --format '%A', I obtain a result with format drwxrws---, human readable

I need a command to obtain a format like u=rwx,g=srwx,o-rwx (compatible with chmod symbolic modes )

  • [u|g|o] : for user/group/other or a for all
  • [=] : for rights granted
  • [rwxst] : list of rights granted no order importance
  • [-rwx] :for right revoked (if no right granted)

I have tried this ( But it doesn't handle all cases, specialy sticky bits) :

stat --format '%A' temp |
    sed -E 's/^.(...)(...)(...)/u=\1,g=\2,o=\3/g' | # split by triplet
    sed 's/=---/-rwx/g' | # revoker grants
    sed 's/rws/srwx/g'  | # setgid with x ...
    sed 's/--S/s/g'     | # setgid without x ...
    sed ... nead more transormation... # manage  sticky bit setuid setgid

I search a more elegant way.

example input ==> output

  • drwxrws--- ==> u=rwx,g=srwx,o-rwx (begin by d ==> directory)
  • drwxrwxrwx ==> u=rwx,g=rwx,o=rwx or ugo=rwx or a=rwx
  • -r-xrw-r-- ==> u=rx,g=rw,o=r (begin by - ==> regular file)
  • -rwx--S--- ==> u=rwx,g=s,o-rwx (S in uppercase)
  • ------s--t ==> u=-srwx,g=sx,o=xt (Stickybit)

input format ==> like commands stat or ls -al
output format==> must be compatible with chmod

This complete version seems works, but I'm sure we can simplify it, ( ie without multiple sed )

stat --format '%A' a |
sed -E 's/^.(...)(...)(...)/u=\1,g=\2,o=\3/g' | # split by triplet    
sed -E 's/s/xs/g'          | # setgid ou setuid with x ...
sed -E 's/t/xt/g'          | # sticky bit with x ...    
sed -E 's/S/s/g'           | # setgid ou setuid without x ...
sed -E 's/T/t/g'           | # sticky bit alone
sed -E 's/-//g'            | # remove -
sed -E 's/=(,|$)/-rwx\1/g'   # revoker grants
Indent
  • 4,675
  • 1
  • 19
  • 35

2 Answers2

2

The sed command takes multiple -e 'sed-command' options, so it is trivial to fix your code so that it uses one invocation of sed:

stat --format '%A' a |
sed -E -e 's/^.(...)(...)(...)/u=\1,g=\2,o=\3/g' \
       -e 's/s/xs/g' \
       -e 's/t/xt/g' \    
       -e 's/S/s/g' \
       -e 's/T/t/g' \
       -e 's/-//g' \
       -e 's/=(,|$)/-rwx\1/g'

You can't use the trailing comments, but this is otherwise the same as what you showed. Your s/s/xs/g operation doesn't match what you describe as the output you want (you show sx and not xs for the SGID with group execute permissions). There are those who'd smush all those options into a single -e option with semicolons separating the expressions. I prefer to use -e to separate separate options. There are times when the -f script.sed option to read the script from a file is sensible. I don't think this script has reached that threshold yet, but don't forget that the option exists.

Beauty is in the eye of the beholder. I'm not convinced that the alternative representation for permissions is very much better than the normal one, but maybe I've just been using Unix too long.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thanks for your proposal, I known already different syntax of sed. I have used 'multiple' command to add easly comments. For `xs`vs `sx` the order is not important. For the choice of the alternative format, I think the `symbolic` syntax is more clear when we use sticky bit, the upper case `S`and `T` vs `s` and `t` is a hack for me, because initially unix don't manage the sticky bit. I Will complet my question to detail the raison. – Indent Oct 21 '17 at 11:36
2

Finally the more concise command I have found is :

stat --format '%A' myFile | sed -E -e 's/(...)(...)(...)$/u=\1,g=\2,o=\3/;s/(s|t)/x\1/g;s/(S|T)/\l\1/g;s/-//g;s/(u|g)=,/\1-rwxs,/g;s/o=$/o-rwxt/g'

I would have preferred to find a native command

To be sure I have written an exhaustive bash to test all combination of rights (8*8*8*8 = 4096 cases !)

test_file=/tmp/a

return_code=0

echo -e "from itertools import product;\nfor mod in  product('01234567', repeat=4) : print ''.join(mod)" | python | shuf |
while read octalMod
do
  chmod $octalMod $test_file  # apply octal mod

  # get symbolic mod
  symbolicMod=$(stat --format '%A' $test_file | sed -E -e 's/(...)(...)(...)$/u=\1,g=\2,o=\3/;s/(s|t)/x\1/g;s/(S|T)/\l\1/g;s/-//g;s/(u|g)=,/\1-rwxs,/g;s/o=$/o-rwxt/g')

  chmod 0000 $test_file          # reset mod
  chmod $symbolicMod $test_file  # apply symbolic mod

  modActual=$(stat --format '%a' $test_file) # get actual mod in octal format to compare it with the original
  if [ $octalMod -ne $modActual ]
  then
    echo "$octalMod ($symbolicMod) !!! octalMod=$octalMod <> modActual=$modActual" >&2
    return_code=255
  else
    echo "$octalMod ($symbolicMod)     octalMod=$octalMod == modActual=$modActual" >&1
  fi

done
exit $return_code

Complete list :

test_file=/tmp/a

echo -e "octalMod\thumanMod\tsymbolicMod"

echo -e "from itertools import product;\nfor mod in  product('01234567', repeat=4) : print ''.join(mod)" | python |
while read octalMod
do
  chmod $octalMod $test_file  # apply octal mod

  # get symbolic mod
  symbolicMod=$(stat --format '%A' $test_file | sed -E -e 's/(...)(...)(...)$/u=\1,g=\2,o=\3/;s/(s|t)/x\1/g;s/(S|T)/\l\1/g;s/-//g;s/(u|g)=,/\1-rwxs,/g;s/o=$/o-rwxt/g')
  humanMod=$(stat --format '%A' $test_file)

  echo -e "$octalMod\t$humanMod\t$symbolicMod"

done

echo -e "octalMod\thumanMod\tsymbolicMod"

sample result :

octalMod        humanMod        symbolicMod
0001    ---------x      u-rwxs,g-rwxs,o=x
0354    --wxr-xr--      u=wx,g=rx,o=r
1210    --w---x--T      u=w,g=x,o=t
3337    --wx-wsrwt      u=wx,g=wxs,o=rwxt
3566    -r-xrwSrwT      u=rx,g=rws,o=rwt
3734    -rwx-wsr-T      u=rwx,g=wxs,o=rt
6734    -rws-wsr--      u=rwxs,g=wxs,o=r
7121    ---s-wS--t      u=xs,g=ws,o=xt
7430    -r-S-ws--T      u=rs,g=wxs,o=t
7611    -rwS--s--t      u=rws,g=xs,o=xt
Indent
  • 4,675
  • 1
  • 19
  • 35