Konvertiert das Ausgabeformat ls -l in das Format chmod

17

Angenommen, ich habe die folgende Ausgabe von ls -l:

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

Wie kann ich dies automatisch in das von verwendete Format konvertieren chmod?

Beispielsweise:

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

Ich verwende OS X 10.8.3.

Tyilo
quelle
2
Viel einfacher mit stat. Hast Du es? (Es ist ein GNU-Tool, das hauptsächlich unter Linux und nicht unter Unix verfügbar ist.)
manatwork
@manatwork stat foogibt 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. Ich sehe es nicht 755.
Tyilo

Antworten:

24

Einige Systeme haben Befehle, um die Berechtigungen einer Datei als Nummer anzuzeigen, aber leider nichts portierbares.

zshhat ein stat(aka zstat) eingebautes statModul:

zmodload zsh/stat
stat -H s some-file

Dann ist das modein $s[mode]aber ist der Modus, das heißt Typ + Dauerwellen.

Wenn Sie die in Oktal ausgedrückten Berechtigungen möchten, benötigen Sie:

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

BSDs (einschließlich Apple OS / X ) verfügen ebenfalls über einen statBefehl.

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

GNU find (von 1990 und wahrscheinlich früher) kann die Berechtigungen als Oktal ausgeben:

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

Später (2001, lange nach zsh stat(1997), aber vor BSD stat(2002)) wurde ein GNU- statBefehl mit einer anderen Syntax eingeführt:

stat -c %a some-file

Lange zuvor hatte IRIX bereits einen statBefehl (bereits 1994 in IRIX 5.3 vorhanden ) mit einer anderen Syntax:

stat -qp some-file

Wenn es keinen Standardbefehl gibt, ist die beste Option für die Portabilität die Verwendung von perl:

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

Sie können GNU statauffordern, die Berechtigungen im oktalen Format auszugeben, indem Sie die -cOption verwenden. Von 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

Also in deinem Fall:

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

Oder Sie können es sogar automatisieren, indem Sie statdie Ausgabe als gültigen Befehl formatieren :

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

Die obige Lösung funktioniert auch für mehrere Dateien, wenn ein Platzhalter verwendet wird:

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

Funktioniert ordnungsgemäß mit Dateinamen, die Leerzeichen enthalten, schlägt jedoch bei Dateinamen mit einfachen Anführungszeichen fehl.

Mann bei der Arbeit
quelle
2
Ich stathabe keine -cOption. Ich verwende OS X 10.8.3.
Tyilo
Danke für die Information, @Tyilo. Und sorry, ich kann nicht mit den Tools von OS X helfen.
Manatwork
Versuchen Sie, die Manpage ^ W ^ W ^ W stat (1) unter Mac OS X mit dem Flag -f stat -f 'chmod %p "%N"'
gelraen
11

Um von der symbolischen in die oktale Notation zu konvertieren, habe ich mir einmal Folgendes ausgedacht :

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

Erweitert:

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

Das gibt die Oktalzahl aus der Ausgabe ls -leiner Datei zurück.

$ echo 'drwSr-sr-T' | chmod_format
7654
Stéphane Chazelas
quelle
Ich habe dies für die Ausgabe von verwendet dpkg, um die Berechtigungen auf "wie installiert" zurückzusetzen. Vielen Dank für die Beantwortung der Frage, unabhängig davon, mit welchem ​​Befehl die Berechtigungszeichenfolge erstellt wurde.
HiTechHiTouch
3

Dieser Befehl unter Mac sh

stat -f "%Lp %N" your_files

Wenn Sie nur die numerische Berechtigung möchten, verwenden Sie nur% Lp.

beispielsweise:

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

Der 700 ist die numerische Berechtigung, die in chmod verwendet werden kann, und Desktop ist der Dateiname.

TonyL2ca
quelle
2

Hier ist eine Antwort auf Frage Y (ohne Rücksicht auf Frage X ), inspiriert von dem Versuch des 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

Das Obige enthält ein paar Bashismen. Die folgende Version scheint POSIX-kompatibel zu sein:

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

Anmerkungen:

  • Das LC_COLLATE=Cweist die Shell an, Buchstabenfolgenmuster wie in der ASCII-Reihenfolge zu behandeln, [a-e]entspricht also [abcde]. In einigen Gebietsschemas (z. B. en_US) [a-e]ist äquivalent zu [aAbBcCdDeE] (dh [abcdeABCDE]) oder vielleicht [abcdeABCD]- siehe Warum unterscheidet die Bash-Case-Anweisung nicht zwischen Groß- und Kleinschreibung? )
  • In der zweiten Version (der POSIX-kompatiblen):

    • Die erste caseAussage könnte umgeschrieben werden:

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

      Aber ich denke, die Art und Weise, wie ich es jetzt habe, macht es einfacher zu sehen, dass l der Brief anders gehandhabt wird. Alternativ könnte es umgeschrieben werden:

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

      da r, w, x, s, und tsind die einzigen Buchstaben , die jemals in einem Modus Zeichenfolge (außer erscheinen sollen l).

    • Die zweite caseAussage könnte umgeschrieben werden:

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

      um die Regel durchzusetzen, dass nur Buchstaben für die Angabe von Modusbits gültig sind. (Im Gegensatz dazu ist die prägnantere Version im vollständigen Skript faul und wird -rw@rw#rw%als äquivalent zu  akzeptiert rwSrwSrwT.) Alternativ könnte sie umgeschrieben werden:

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

      da S, s, T, t, L, und lsind die einzigen Buchstaben , die jemals in einem Modus Zeichenfolge (außer erscheinen sollen r, wund x).

Verwendung:

$ 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

Und ja, ich weiß, dass es besser ist, keinen echoText zu verwenden, der damit beginnt -. Ich wollte nur das Anwendungsbeispiel aus der Frage kopieren. Beachten Sie , offensichtlich, dass dies ignoriert die 0 - ten Zeichen (dh der führenden d/ b/ c/ -/ l/ p/ s/ D) und der 10. ( +/ ./ @). Es wird davon ausgegangen, dass die Betreuer von lsniemals r/ Roder w/ Wals gültige Zeichen in der dritten, sechsten oder neunten Position definieren werden (und wenn dies der Fall ist, sollten sie mit Stöcken geschlagen werden ).


Außerdem habe ich gerade den folgenden Code von cas unter So stellen Sie die standardmäßige Gruppen- / Benutzereigenschaft aller Dateien unter / var wieder her :

        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 ))

Ich habe diesen Code getestet (aber nicht gründlich), und es scheint zu funktionieren, abgesehen von der Tatsache, dass er nicht erkannt wird loder Lan sechster Stelle steht. Beachten Sie jedoch, dass meine Antwort zwar in Bezug auf Einfachheit und Klarheit überlegen ist, meine jedoch kürzer ist (nur der Code in der Schleife wird gezählt; der Code, der eine einzelne -rwxrwxrwxZeichenfolge verarbeitet, ohne Kommentare zu zählen) durch Ersetzen durch .if condition; then …condition && …


Natürlich solltenls Sie die Ausgabe von nicht analysieren .

Scott
quelle
@ StéphaneChazelas: OK, ich sagte #!/bin/shund benutzte dann ein paar Bashismen. Hoppla. Aber Sie haben ein paar verpasst: und scheinen auch kein POSIX zu sein (der Standard erwähnt überhaupt nichts und ist eichhörnchengeschützt auf und ). Umgekehrt habe ich nicht verwendet ; dass nur in erscheint cas ‚s Antwort, die ich zitierte von hier . Auch meine Antwort tut Griff ‚l‘ und ‚L‘, und ich bereits darauf hingewiesen , dass cas Antwort nicht. $(( variable++ ))$(( number ** number ))**++-- [[…]]
Scott
Tut mir leid wegen l / L [[, ich habe zu schnell gelesen. Ja, - und ++ sind kein POSIX. Mit POSIX können Shells sie implementieren. Das heißt, Sie müssen schreiben, $((- -a))wenn Sie eine doppelte Negation wünschen, und nicht, wenn Sie $((--a))eine Dekrementierungsoperation meinen.
Stéphane Chazelas
Beachten Sie, dass dies seqkein POSIX-Befehl ist. Möglicherweise können Sie den Operator $ {var #?} Verwenden, um Ausdruck zu vermeiden. Nicht, dass LC_COLLATE LC_ALL nicht überschreibt
Stéphane Chazelas
@ StéphaneChazelas: OK, du sprichst jetzt wieder von Cas 'Antwort, oder? Er verwendet den "faulen" Ansatz, mit Dezimalarithmetik einen String zu konstruieren, der wie eine Oktalzahl aussieht. Beachten Sie, dass alle seine Schrittwerte (4000, 2000, 1000, 400, 200, 100, 40, 20 und 10) Dezimalzahlen sind. Aber da es keine 8oder keine gibt 9und es keine Möglichkeit gibt, mehr als 7eine Dezimalstelle zu erreichen, kann er von der Scharade abziehen. …………………… (Dieser Kommentar ist eine Antwort auf einen Kommentar von Stéphane Chazelas, der verschwunden ist.)
Scott
Ja, das habe ich später gemerkt, weshalb ich den Kommentar gelöscht habe.
Stéphane Chazelas
1

Wenn es Ihr Ziel ist, Berechtigungen von einer Datei zu übernehmen und sie auch einer anderen zu geben, hat GNU chmodbereits eine "Referenz" -Option dafür .

Bratchley
quelle
Das OP erwähnte, dass er auf Apple OS / X war, also chmodwird die GNU chmoddort nicht sein .
Stéphane Chazelas
Ah ja ich sehe den Kommentar auf der anderen Antwort, wo sie ihre Plattform sagen. Meins ist jedoch nicht das einzige, das GNU erwähnt, und Sie können GNU Utilities unter Mac OS X
Bratchley am
0

Eine Alternative, wenn Sie die Berechtigungen speichern möchten, um sie später wiederherzustellen, oder für eine andere Datei, ist die Verwendung setfacl/getfacl, und es werden auch (POSIX-Entwurfs-) ACLs als Bonus wiederhergestellt.

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

(Verwenden Sie unter Solaris -fanstelle von -M).

Sie sind zwar auf einigen BSDs verfügbar, jedoch nicht auf Apple OS / X, wo die ACLs chmodnur bearbeitet werden .

Stéphane Chazelas
quelle
0

Unter Mac OS X (10.6.8) müssen Sie verwenden stat -f format(da es sich tatsächlich um NetBSD / FreeBSD handelt 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"

Um nur eine symbolische Berechtigungszeichenfolge zu übersetzen, die von ls -lin octal erzeugt wurde (nur mit Shell-Builtins), siehe: showperm.bash .

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