Convertir le format de sortie ls -l en format chmod

Dire que j'ai la sortie suivante de ls -l :

 drwxr-xr-x 2 root root 4096 Apr 7 17:21 foo 

Comment puis-je convertir automatiquement le file au format utilisé par chmod ?

Par exemple:

 $ echo drwxr-xr-x | chmod-format 755 

J'utilise OS X 10.8.3.

Certains systèmes ont des commands pour afficher les permissions d'un file en tant que nombre, mais malheureusement, rien de portable.

zsh a une stat (aka zstat ) embeddede dans le module stat :

 zmodload zsh/stat stat -H s some-file 

Ensuite, le mode est en $s[mode] mais c'est le mode, c'est le type + perms.

Si vous voulez les permissions exprimées en octal, vous avez besoin de:

 perms=$(([##8] s[mode] & 8#7777)) 

Les BSD (y compris Apple OS / X ) ont également une command stat .

 mode=$(stat -f %p some-file) perm=$(printf %o "$((mode & 07777))" 

GNU find (à partir de 1990 et probablement avant) peut imprimer les permissions comme octal:

 find some-file -prune -printf '%m\n' 

Plus tard (2001, longtime après zsh stat (1997) mais avant BSD stat (2002)), une command GNU stat été introduite avec une syntaxe différente:

 stat -c %a some-file 

Bien avant cela, IRIX disposait déjà d'une command stat (déjà disponible dans IRIX 5.3 en 1994) avec une autre syntaxe:

 stat -qp some-file 

Encore une fois, quand il n'y a pas de command standard, le meilleur pari pour la portabilité est d'utiliser perl :

 perl -e 'printf "%o\n", (stat shift)[2]&07777' some-file 

Vous pouvez requestr à GNU stat de sortir les permissions au format octal en utilisant l'option -c . De l' man stat :

  -c --format=FORMAT use the specified FORMAT instead of the default; output a newline after each use of FORMAT ⋮ %a access rights in octal ⋮ %n file name 

Donc dans votre cas:

 bash-4.2$ ls -l foo -rw-r--r-- 1 manatwork manatwork 0 Apr 7 19:43 foo bash-4.2$ stat -c '%a' foo 644 

Ou vous pouvez même l'automatiser en formattant la sortie de stat comme command valide:

 bash-4.2$ stat -c "chmod %a '%n'" foo chmod 644 'foo' bash-4.2$ stat -c "chmod %a '%n'" foo > setpermission.sh bash-4.2$ chmod a= foo bash-4.2$ ls -l foo ---------- 1 manatwork manatwork 0 Apr 7 19:43 foo bash-4.2$ sh setpermission.sh bash-4.2$ ls -l foo -rw-r--r-- 1 manatwork manatwork 0 Apr 7 19:43 foo 

La solution ci-dessus fonctionnera également pour plusieurs files si vous utilisez un caractère générique:

 stat -c "chmod -- %a '%n'" -- * 

Fonctionne correctement avec les noms de files contenant des caractères blancs, mais échouera sur les noms de files contenant des guillemets simples.

Pour passer de la notation symbolique à la notation octale, j'ai une fois trouvé :

 chmod_format() { sed 's/.\(.........\).*/\1/ h;y/rwsxtSTlL-/IIIIIOOOOO/;x;s/..\(.\)..\(.\)..\(.\)/|\1\2\3/ y/sStTlLx-/IIIIIIOO/;G s/\n\(.*\)/\1;OOO0OOI1OIO2OII3IOO4IOI5IIO6III7/;:k s/|\(...\)\(.*;.*\1\(.\)\)/\3|\2/;tk s/^0*\(..*\)|.*/\1/;q' } 

Étendu:

 #! /bin/sed -f s/.\(.........\).*/\1/; # extract permissions and discard the rest h; # store a copy on the hold space # Now for the 3 lowest octal digits (rwx), translates the flags to # binary where O means 0 and I means 1. # l, L are for mandatory locking (a regular file that has 02000 on # and not 010 on some systems like Linux). Some ls implementations # like GNU ls confusingly use S there like for directories even though # it has nothing to do with setgid in that case. Some ls implementations # use L, some others l (against POSIX which requires an uppercase # flag for extra flags when the execution bit is not set). y/rwsxtSTlL-/IIIIIOOOOO/ x; # swap hold and pattern space, to do a second processing on those flags. # now only consider the "xXlLsStT" bits: s/..\(.\)..\(.\)..\(.\)/|\1\2\3/ y/sStTlLx-/IIIIIIOO/; # make up the 4th octal digit as binary like before G; # append the hold space so we now have all 4 octal digits as binary # remove the extra newline and append a translation table s/\n\(.*\)/\1;OOO0OOI1OIO2OII3IOO4IOI5IIO6III7/ :k # translate the OOO -> 0 ... III -> 7 in a loop s/|\(...\)\(.*;.*\1\(.\)\)/\3|\2/ tk # sortingm leading 0s and our translation table. s/^0*\(..*\)|.*/\1/;q 

Cela renvoie le nombre octal de la sortie de ls -l sur un file.

 $ echo 'drwSr-sr-T' | chmod_format 7654 

Cette command sur Mac sous sh

 stat -f "%Lp %N" your_files 

si vous ne souhaitez que l'autorisation numérique, utilisez% Lp uniquement.

par exemple:

 stat -f "%Lp %N" ~/Desktop 700 Desktop 

Le 700 est l'autorisation numérique qui peut être utilisée dans chmod, et Desktop est le nom de file.

Voici une réponse à la question Y (en ignorant la question X ), inspirée par la tentative de l'OP:

 #!/bin/bash LC_COLLATE=C while read ls_out do extra=0 perms=0 for i in {1..9} do # Shift $perms to the left one bit, so we can always just add the LSB. let $((perms*=2)) this_char=${ls_out:i:1} # If it's different from its upper case equivalent, # it's a lower case letter, so the bit is set. # Unless it's "l" (lower case L), which is special. if [ "$this_char" != "${this_char^}" ] && [ "$this_char" != "l" ] then let $((perms++)) fi # If it's not "r", "w", "x", or "-", it indicates that # one of the high-order (S/s=4000, S/s/L/l=2000, or T/t=1000) bits # is set. case "$this_char" in ([^rwx-]) let $((extra += 2 ** (3-i/3) )) esac done printf "%o%.3o\n" "$extra" "$perms" done 

Ce qui précède contient quelques bashismes. La version suivante semble être conforme à POSIX:

 #!/bin/sh LC_COLLATE=C while read ls_out do extra=0 perms=0 for i in $(seq 1 9) do # Shift $perms to the left one bit, so we can always just add the LSB. : $((perms*=2)) this_char=$(expr "$ls_out" : ".\{$i\}\(.\)") # Lower case letters other than "l" indicate that permission bits are set. # If it's not "r", "w", "x", or "-", it indicates that case "$this_char" in (l) ;; ([az]) : $((perms+=1)) esac # If it's not "r", "w", "x", or "-", it indicates that # one of the high-order (S/s=4000, S/s/L/l=2000, or T/t=1000) bits # is set. case "$this_char" in ([!rwx-]) : $((extra += 1 << (3-i/3) )) esac done printf "%o%.3o\n" "$extra" "$perms" done 

Remarques:

  • LC_COLLATE=C indique à l'interpréteur de commands de traiter les templates de plage de séquence de lettres en utilisant l'ordre ASCII, donc [ae] équivaut à [abcde] . Dans certains contexts (eg, en_US), [ae] est équivalent à [aAbBcCdDeE] (c.-à-d. [abcdeABCDE] ) ou peut-être [abcdeABCD] – voir Pourquoi l'instruction de cas bash ne [abcdeABCD] pas la casse …? )
  • Dans la deuxième version (celle conforme à POSIX):

    • Le premier énoncé de case pourrait être réécrit:

        case "$this_char" in ([a-km-z]) : $((perms+=1)) esac 

      mais je pense que la façon dont je l'ai maintenant rend plus facile de voir que l suis la lettre qui est traitée différemment. Alternativement, il pourrait être réécrit:

        case "$this_char" in ([rwxst]) : $((perms+=1)) esac 

      puisque r , w , x , s et t sont les seules lettres qui devraient apparaître dans une string de mode (autre que l ).

    • La deuxième déclaration de case pourrait être réécrite:

        case "$this_char" in ([rwx]) ;; ([A-Za-z]) : $((extra += 1 << (3-i/3) )) esac 

      pour appliquer la règle selon laquelle seules les lettres sont valides pour spécifier les bits de mode. (Par contre, la version plus succincte du script complet est paresseuse et acceptera -rw@rw#rw% comme équivalent à rwSrwSrwT .) Sinon, il pourrait être réécrit:

        case "$this_char" in ([SsTtLl]) : $((extra += 1 << (3-i/3) )) esac 

      puisque S , s , T , t , L et l sont les seules lettres qui devraient apparaître dans une string de mode (autre que r , w et x ).

Usage:

 $ echo drwxr-xr-x | chmod-format 0755 $ echo -rwsr-sr-x | chmod-format 6755 $ echo -rwSr-Sr-- | chmod-format 6644 $ echo -rw-r-lr-- | chmod-format 2644 $ echo ---------- | chmod-format 0000 

Et, oui, je sais qu'il vaut mieux ne pas utiliser d' echo avec du text qui pourrait commencer par - ; Je voulais juste copyr l'exemple d'utilisation de la question. Notez bien évidemment que cela ne tient pas count du 0e caractère (c'est-à-dire du premier d / b / c / - / l / p / s / D ) et du 10e ( + / . / @ ). Il suppose que les mainteneurs de ls ne définissent jamais r / R ou w / W comme des caractères valides dans la troisième, la sixième ou la neuvième position (et, s'ils le font, ils doivent être battus avec des bâtons ).


En outre, je viens de find le code suivant, par cas , sous Comment restaurer la propriété par défaut de groupe / user de tous les files sous / var :

  let perms=0 [[ "${ssortingng}" = ?r???????? ]] && perms=$(( perms + 400 )) [[ "${ssortingng}" = ??w??????? ]] && perms=$(( perms + 200 )) [[ "${ssortingng}" = ???x?????? ]] && perms=$(( perms + 100 )) [[ "${ssortingng}" = ???s?????? ]] && perms=$(( perms + 4100 )) [[ "${ssortingng}" = ???S?????? ]] && perms=$(( perms + 4000 )) [[ "${ssortingng}" = ????r????? ]] && perms=$(( perms + 40 )) [[ "${ssortingng}" = ?????w???? ]] && perms=$(( perms + 20 )) [[ "${ssortingng}" = ??????x??? ]] && perms=$(( perms + 10 )) [[ "${ssortingng}" = ??????s??? ]] && perms=$(( perms + 2010 )) [[ "${ssortingng}" = ??????S??? ]] && perms=$(( perms + 2000 )) [[ "${ssortingng}" = ???????r?? ]] && perms=$(( perms + 4 )) [[ "${ssortingng}" = ????????w? ]] && perms=$(( perms + 2 )) [[ "${ssortingng}" = ?????????x ]] && perms=$(( perms + 1 )) [[ "${ssortingng}" = ?????????t ]] && perms=$(( perms + 1001 )) [[ "${ssortingng}" = ?????????T ]] && perms=$(( perms + 1000 )) 

J'ai testé ce code (mais pas complètement), et il semble fonctionner, sauf le fait qu'il ne reconnaît pas l ou L dans la sixième position. Notez cependant que bien que cette réponse soit supérieure en termes de simplicité et de clarté, la mienne est en fait plus courte (countr uniquement le code à l' intérieur de la boucle, le code qui gère une seule string -rwxrwxrwx , sans countr les commentaires) encore plus courte en remplaçant if condition ; then … if condition ; then … avec la condition && …


Bien sûr, vous ne devriez pas parsingr la sortie de ls .

Si votre but est de prendre les permissions d'un file et de les donner à un autre, GNU chmod déjà une option de "reference" pour cela .

Sur Mac OS X (10.6.8), vous devez utiliser le stat -f format (car il s'agit en fait de NetBSD / FreeBSD stat ).

 # using Bash mods="$(stat -f "%p" ~)" # octal notation mods="${mods: -4}" echo "$mods" mods="$(stat -f "%Sp" ~)" # symbolic notation mods="${mods: -9}" echo "$mods" 

Pour traduire simplement une string de permission symbolique produite par ls -l en octal (en utilisant uniquement les builtins de shell), voir: showperm.bash .

 # from: showperm.bash # usage: showperm modessortingng # # example: showperm '-rwsr-x--x' 

Si vous voulez sauvegarder les permissions, les restaurer ultérieurement ou utiliser un file différent, utilisez setfacl/getfacl et restaurez également les ACL (POSIX-draft) en tant que bonus.

 getfacl some-file > saved-perms setfacl -M saved-perms some-other-file 

(sur Solaris, utilisez -f au lieu de -M ).

Cependant, bien qu'ils soient disponibles sur certains BSD, ils ne sont pas sous Apple OS / X où les ACL sont manipulés uniquement avec chmod .