Convertir le format de sortie ls -l au format chmod

17

Disons 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 cela au format utilisé par chmod?

Par exemple:

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

J'utilise OS X 10.8.3.

Tyilo
la source
2
Beaucoup plus facile avec stat. L'avez vous? (C'est un outil GNU, donc principalement disponible sur Linux, pas sur Unix.)
manatwork
@manatwork stat foodonne 16777219 377266 drwxr-xr-x 119 Tyilo staff 0 4046 "Apr 7 17:49:03 2013" "Apr 7 18:08:31 2013" "Apr 7 18:08:31 2013" "Nov 25 17:13:52 2012" 4096 0 0 /Users/Tyilo. Je n'y vois pas 755.
Tyilo

Réponses:

24

Certains systèmes ont des commandes pour afficher les autorisations d'un fichier sous forme de nombre, mais malheureusement, rien de portable.

zsha un stat(aka zstat) intégré dans le statmodule:

zmodload zsh/stat
stat -H s some-file

Ensuite, le modeest dans $s[mode]mais est le mode, c'est-à-dire type + perms.

Si vous souhaitez que les autorisations soient exprimées en octal, vous avez besoin de:

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

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

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

GNU find (d'aussi loin que 1990 et probablement avant) peut imprimer les autorisations en octal:

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

Plus tard (2001, longtemps après zsh stat(1997) mais avant BSD stat(2002)) une statcommande GNU a été introduite avec à nouveau une syntaxe différente:

stat -c %a some-file

Bien avant ceux-ci, IRIX avait déjà une statcommande (déjà là dans IRIX 5.3 en 1994) avec une autre syntaxe:

stat -qp some-file

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

perl -e 'printf "%o\n", (stat shift)[2]&07777' some-file
Stéphane Chazelas
la source
15

Vous pouvez demander à GNU statde sortir les autorisations au format octal en utilisant l' -coption. De 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 formatant statla sortie en tant que commande 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 fichiers si vous utilisez un caractère générique:

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

Fonctionnera correctement avec les noms de fichiers contenant des espaces, mais échouera avec les noms de fichiers contenant des guillemets simples.

homme au travail
la source
2
Mon statn'a pas d' -coption. J'utilise OS X 10.8.3.
Tyilo
Merci pour l'information, @Tyilo. Et désolé, je ne peux pas aider avec les outils d'OS X.
manatwork
Essayez de lire la page de manuel ^ W ^ W ^ W stat (1) sur Mac OS X avec l'indicateur -f pour spécifier le format de sortie, par exemplestat -f 'chmod %p "%N"'
gelraen
11

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

# trim leading 0s and our translation table.
s/^0*\(..*\)|.*/\1/;q

Cela renvoie le nombre octal de la sortie de ls -lsur un fichier.

$ echo 'drwSr-sr-T' | chmod_format
7654
Stéphane Chazelas
la source
Je l'ai utilisé sur la sortie de dpkgpour redéfinir les autorisations sur "tel qu'installé". Merci d'avoir répondu à la question littérale sans tenir compte de la commande qui a produit la chaîne d'autorisation.
HiTechHiTouch
3

Cette commande sur Mac sous sh

stat -f "%Lp %N" your_files

si vous souhaitez uniquement 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 fichier.

TonyL2ca
la source
2

Voici une réponse à la question Y (en ignorant la question X ), inspirée de la tentative du PO:

#!/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 compatible 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)
                        ;;
                  ([a-z])
                        : $((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:

  • Le LC_COLLATE=Cdit au shell de traiter les modèles de plage de séquence de lettres comme utilisant l'ordre ASCII, [a-e]est donc équivalent à [abcde]. Dans certains paramètres régionaux (par exemple, en_US), [a-e]est équivalent à [aAbBcCdDeE] (c.- à -d. [abcdeABCDE]) Ou peut [abcdeABCD]- être - voir Pourquoi l'instruction bash case n'est pas sensible à la casse…? )
  • Dans la deuxième version (celle compatible POSIX):

    • La première casedéclaration pourrait être réécrite:

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

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

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

      depuis r, w, x, set tsont les seules lettres qui devraient jamais apparaître dans une chaîne de mode (autre que l).

    • La deuxième casedéclaration 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. (En revanche, la version la plus succincte du script complet est paresseuse et acceptera -rw@rw#rw%comme équivalente à  rwSrwSrwT.) Alternativement, elle pourrait être réécrite:

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

      depuis S, s, T, t, Let lsont les seules lettres qui devraient jamais apparaître dans une chaîne de mode (autres que r, wet 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 echoavec du texte qui pourrait commencer -; Je voulais juste copier l'exemple d'utilisation de la question. Notez, bien entendu, que cela ignore le 0ème caractère (c'est-à-dire le premier d/ b/ c/ -/ l/ p/ s/ D) et le 10ème ( +/ ./ @). Il suppose que les mainteneurs de lsne définiront jamais r/ Rou w/ Wcomme des caractères valides en troisième, sixième ou neuvième position (et, s'ils le font, ils devraient être battus avec des bâtons ).


En outre, je viens de trouver le code suivant, par cas , sous Comment restaurer la propriété par défaut du groupe / utilisateur de tous les fichiers sous / var :

        let perms=0

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

J'ai testé ce code (mais pas complètement), et il semble fonctionner, sauf qu'il ne reconnaît pas lou Len 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 (en comptant uniquement le code à l' intérieur de la boucle; le code qui gère une seule -rwxrwxrwxchaîne, sans compter les commentaires), et elle pourrait être encore plus courte en remplaçant par .if condition; then …condition && …


Bien sûr, vous nels devez pas analyser la sortie de .

Scott
la source
@ StéphaneChazelas: OK, j'ai dit #!/bin/shpuis utilisé quelques bashismes. Oups. Mais vous en avez raté quelques-uns: et ne semblez pas non plus être POSIX (le Standard ne le mentionne pas du tout, et est écervelé et ). Inversement, je n'ai pas utilisé ; qui apparaît uniquement dans CAS réponse de l », que je citais d' ici . De plus, ma réponse gère les «l» et «L», et j'ai déjà souligné le fait que la réponse de cas ne le fait pas. $(( variable++ ))$(( number ** number ))**++-- [[…]]
Scott
Désolé pour l / L [[, j'ai lu trop rapidement. Oui, - et ++ ne sont pas POSIX. POSIX permet aux shells de les implémenter, cela signifie que vous devez écrire $((- -a))si vous voulez une double négation, pas que vous pouvez utiliser $((--a))pour signifier une opération de décrémentation.
Stéphane Chazelas
Notez qu'il seqne s'agit pas d'une commande POSIX. Vous pourrez peut-être utiliser l'opérateur $ {var #?} Pour éviter expr. Non pas que LC_COLLATE n'écrase pas LC_ALL
Stéphane Chazelas
@ StéphaneChazelas: OK, tu parles à nouveau de la réponse de cas maintenant, non? Il adopte l'approche "paresseuse" de l'utilisation de l'arithmétique décimale pour construire une chaîne qui ressemble à un nombre octal. Notez que toutes ses valeurs de pas (4000, 2000, 1000, 400, 200, 100, 40, 20 et 10) sont des nombres décimaux. Mais, puisqu'il n'y a pas de 8«ou 9», et aucun moyen d'obtenir plus que 7dans n'importe quelle position décimale, il peut tirer de la mascarade. …………………… (Ce commentaire est une réponse à un commentaire de Stéphane Chazelas qui a disparu.)
Scott
Oui, je m'en suis rendu compte plus tard, c'est pourquoi j'ai supprimé le commentaire.
Stéphane Chazelas
1

Si votre objectif est de prendre les permissions d'un fichier et de les donner à un autre également, GNU a chmoddéjà une option "référence" pour cela .

Bratchley
la source
L'OP a mentionné qu'il était sur Apple OS / X, il chmodn'y aura donc pas de GNU chmod.
Stéphane Chazelas
Ah ouais je vois le commentaire sur l'autre réponse où ils disent leur plateforme. Le mien n'est pas le seul à mentionner GNU et vous pouvez obtenir les utilitaires GNU sur Mac OS X
Bratchley
0

Une alternative, si vous souhaitez enregistrer les autorisations, pour les restaurer plus tard, ou sur un fichier différent est à utiliser setfacl/getfacl, et il restituera également (ACL POSIX) en tant que bonus.

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

(sous Solaris, utilisez -fplutôt que -M).

Cependant, bien qu'ils soient disponibles sur certains BSD, ils ne le sont pas sur Apple OS / X où les ACL sont manipulées chmoduniquement.

Stéphane Chazelas
la source
0

Sur Mac OS X (10.6.8), vous devez utiliser 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 chaîne d'autorisation symbolique produite par ls -len octal (en utilisant uniquement les commandes internes du shell), voir: showperm.bash .

# from: showperm.bash
# usage: showperm modestring
#
# example: showperm '-rwsr-x--x'
phil32
la source