Converti il ​​formato di output ls -l nel formato chmod


17

Di 'che ho il seguente output da ls -l:

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

Come posso convertirlo automaticamente nel formato utilizzato da chmod?

Per esempio:

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

Sto usando OS X 10.8.3.


2
Molto più facile con stat. Ce l'hai? (È uno strumento GNU, quindi per lo più disponibile su Linux, non su Unix.)
manatwork

@manatwork stat foo16777219 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. Non ci vedo 755dentro.
Tyilo

Risposte:


24

Alcuni sistemi dispongono di comandi per visualizzare le autorizzazioni di un file come numero, ma purtroppo nulla di portatile.

zshha un stat(aka zstat) incorporato nel statmodulo:

zmodload zsh/stat
stat -H s some-file

Quindi, modeè presente $s[mode]ma è la modalità, ovvero tipo + permanenti.

Se si desidera che le autorizzazioni siano espresse in ottale, è necessario:

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

Anche i BSD (incluso Apple OS / X ) hanno un statcomando.

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

GNU find (dal lontano 1990 e probabilmente prima) può stampare i permessi come ottali:

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

Più tardi (2001, molto dopo zsh stat(1997) ma prima di BSD stat(2002)) statfu introdotto un comando GNU con una sintassi diversa:

stat -c %a some-file

Molto prima di questi, IRIX aveva già un statcomando (già lì in IRIX 5.3 nel 1994) con un'altra sintassi:

stat -qp some-file

Ancora una volta, quando non esiste un comando standard, la scommessa migliore per la portabilità è usare perl:

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

15

Puoi chiedere a GNU statdi emettere i permessi in formato ottale usando l' -copzione. Da 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

Quindi nel tuo caso:

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

Oppure puoi persino automatizzarlo formattando statl'output come comando valido:

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 soluzione sopra funzionerà anche per più file se si utilizza un carattere jolly:

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

Funzionerà correttamente con nomi di file contenenti caratteri di spazi bianchi, ma non riuscirà su nomi di file contenenti virgolette singole.


2
Il mio statnon ha -cun'opzione. Sto usando OS X 10.8.3.
Tyilo

Grazie per l'informazione, @Tyilo. E scusa, non posso aiutarti con gli strumenti di OS X.
arte

Prova a leggere la manpage ^ W ^ W ^ W stat (1) su Mac OS X ha il flag -f per specificare il formato di output, ad es.stat -f 'chmod %p "%N"'
gelraen

11

Per passare dalla notazione simbolica a quella ottale, una volta ho trovato :

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'
}

Allargato:

#! /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

Ciò restituisce il numero ottale dall'output di ls -lsu un file.

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

L'ho usato sull'output di dpkgper impostare le autorizzazioni su "come installato". Grazie per aver risposto alla domanda letterale senza riguardo a quale comando ha prodotto la stringa di autorizzazione.
HiTechHiTouch

3

Questo comando su Mac sotto sh

stat -f "%Lp %N" your_files

se si desidera solo l'autorizzazione numerica, utilizzare solo% Lp.

per esempio:

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

700 è l'autorizzazione numerica che può essere utilizzata in chmod e Desktop è il nome file.


2

Ecco una risposta alla domanda Y (ignorando la domanda X ), ispirata al tentativo del 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

Quanto sopra contiene alcuni bashismi. La seguente versione sembra essere conforme a 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

Appunti:

  • Il LC_COLLATE=Cindica alla shell di lettera trattare modelli gamma sequenza utilizzando l'ordine ASCII, quindi [a-e]è equivalente a [abcde]. In alcune versioni locali (ad es. En_US), [a-e]è equivalente a [aAbBcCdDeE] (ovvero, [abcdeABCDE]) o forse [abcdeABCD]- vedi Perché l'istruzione case bash non è sensibile al maiuscolo / minuscolo ...? )
  • Nella seconda versione (quella conforme a POSIX):

    • La prima caseaffermazione potrebbe essere riscritta:

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

      ma penso che il modo in cui lo ho ora rende più facile vedere che l è la lettera che viene gestita in modo diverso. In alternativa, potrebbe essere riscritto:

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

      dal momento che r, w, x, s, e tsono le uniche lettere che dovrebbe mai apparire in una stringa di modalità (diverso l).

    • La seconda caseaffermazione potrebbe essere riscritta:

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

      per imporre la regola secondo cui solo le lettere sono valide per specificare i bit della modalità. (Al contrario, la versione più succinta dell'intero script è pigra e accetterà -rw@rw#rw%come equivalente a  rwSrwSrwT.) In alternativa, potrebbe essere riscritta:

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

      dal momento che S, s, T, t, L, e lsono le uniche lettere che dovrebbe mai apparire in una stringa di modalità (diversi r, we x).

Uso:

$ 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

E sì, so che è meglio non usare il echotesto che potrebbe iniziare -; Volevo solo copiare l'esempio di utilizzo dalla domanda. Nota, ovviamente, che questo ignora il 0 ° carattere (cioè, il d/ b/ c/ -/ l/ p/ s/ iniziale De il 10 ° ( +/ ./ @). Presuppone che i manutentori di lsnon definiranno mai r/ Ro w/ Wcome personaggi validi nella terza, sesta o nona posizione (e, se lo fanno, dovrebbero essere battuti con i bastoni ).


Inoltre, ho appena trovato il seguente codice, per cas , in Come ripristinare la proprietà predefinita di gruppo / utente di tutti i file in / 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 ))

Ho testato questo codice (ma non completamente), e sembra funzionare, tranne per il fatto che non riconosce lo Lin sesta posizione. Si noti, tuttavia, che mentre questa risposta è superiore in termini di semplicità e chiarezza, la mia è in realtà più breve (contando solo il codice all'interno del ciclo; il codice che gestisce una singola -rwxrwxrwxstringa, senza contare i commenti), e potrebbe essere reso ancora più breve sostituendo con .if condition; then …condition && …


Naturalmente, non dovresti analizzare l'output dils .


@ StéphaneChazelas: OK, ho detto #!/bin/she poi ho usato alcuni bashismi. Ops. Ma te ne sei perso un paio: e non sembra nemmeno essere POSIX (lo Standard non menziona affatto, ed è scoiattolo e ). Al contrario, io non ho usato ; questo appare solo nella risposta di Cas , che ho citato da qui . Inoltre, la mia risposta gestisce "l" e "L", e ho già sottolineato il fatto che la risposta di cas no. $(( variable++ ))$(( number ** number ))**++-- [[…]]
Scott,

Mi dispiace per l / L [[, ho letto troppo velocemente. Sì, - e ++ non sono POSIX. POSIX consente alle shell di implementarle, il che significa che è necessario scrivere $((- -a))se si desidera una doppia negazione, non che si possa usare $((--a))per indicare un'operazione di decremento.
Stéphane Chazelas,

Si noti che seqnon è un comando POSIX. Potresti essere in grado di utilizzare l'operatore $ {var #?} Per evitare l'espr. Non che LC_COLLATE non sovrascriverà LC_ALL
Stéphane Chazelas il

@ StéphaneChazelas: OK, stai parlando di nuovo della risposta di Cas ora, giusto? Sta adottando l'approccio "pigro" dell'uso dell'aritmetica decimale per costruire una stringa che assomiglia a un numero ottale. Si noti che tutti i valori dei suoi passi (4000, 2000, 1000, 400, 200, 100, 40, 20 e 10) sono numeri decimali. Ma dato che non ci sono 8"o 9" e non c'è modo di ottenere qualcosa di più che 7in qualsiasi posizione decimale, può tirare la sciarada. ... ... ... ... ... ... ... ... (Questo commento è una risposta a un commento di Stéphane Chazelas che è scomparso.)
Scott

Sì, me ne sono reso conto in seguito, motivo per cui ho eliminato il commento.
Stéphane Chazelas,


0

Un'alternativa, se si desidera salvare le autorizzazioni, ripristinarle in un secondo momento o su un altro file è utilizzare setfacl/getfacle ripristinerà anche gli ACL (bozza POSIX) come bonus.

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

(su Solaris, utilizzare -finvece di -M).

Tuttavia, sebbene siano disponibili su alcuni BSD, non si trovano su Apple OS / X in cui vengono manipolati chmodsolo gli ACL .


0

Su Mac OS X (10.6.8) devi usare stat -f format(perché in realtà è 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"

Per tradurre semplicemente una stringa di autorizzazione simbolica prodotta da ls -lin ottale (usando solo i comandi incorporati della shell) vedere: showperm.bash .

# from: showperm.bash
# usage: showperm modestring
#
# example: showperm '-rwsr-x--x'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.