LS-L çıkış biçimini chmod biçimine dönüştürme


17

Diyelim ki şu çıktıya sahibim ls -l:

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

Bunu otomatik olarak kullanılan biçime nasıl dönüştürebilirim chmod?

Örneğin:

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

OS X 10.8.3 kullanıyorum.


2
İle çok daha kolay stat. Sende var mı? (Bu bir GNU aracıdır, bu yüzden çoğunlukla Linux'ta mevcuttur, Unix'te mevcut değildir.)
manatwork

@manatwork stat fooverir 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. 755İçinde görmüyorum .
Tyilo

Yanıtlar:


24

Bazı sistemlerde bir dosyanın izinlerini sayı olarak görüntüleme komutları vardır, ancak ne yazık ki taşınabilir bir şey yoktur.

zshBir sahiptir stat(aka zstatolarak) yerleşiğini statmodülü:

zmodload zsh/stat
stat -H s some-file

Sonra, modeiçinde $s[mode]ama mod + tür izinleri.

İzinlerin sekizlik olarak ifade edilmesini istiyorsanız, aşağıdakilere ihtiyacınız vardır:

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

BSD'lerin ( Apple OS / X dahil ) de bir statkomutu vardır.

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

GNU find (1990'a kadar ve muhtemelen daha önce) izinleri sekizlik olarak yazdırabilir:

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

Daha sonra (2001, uzun bir süre sonra zsh stat(1997) ancak BSD'den stat(2002) önce bir GNU statkomutu tekrar farklı bir sözdizimiyle tanıtıldı:

stat -c %a some-file

Onlardan çok önce, IRIX'in başka bir sözdizimiyle statzaten bir komutu vardı ( 1994'te IRIX 5.3'te zaten var ):

stat -qp some-file

Yine, standart bir komut olmadığında, taşınabilirlik için en iyi bahis kullanmaktır perl:

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

15

Bu seçeneği statkullanarak GNU'dan izinleri sekizlik biçimde vermesini isteyebilirsiniz -c. Gönderen 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

Yani sizin durumunuzda:

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

Ya da statçıktısını geçerli komut olarak biçimlendirerek otomatikleştirebilirsiniz :

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

Yukarıdaki çözüm, joker karakter kullanılıyorsa birden çok dosya için de çalışır:

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

Boşluk karakterleri içeren dosya adlarıyla düzgün çalışır, ancak tek tırnak içeren dosya adlarında başarısız olur.


2
Benim statbir -cseçeneğim yok. OS X 10.8.3 kullanıyorum.
Tyilo

Bilgi için teşekkürler, @Tyilo. Ve üzgünüm, OS X'in araçlarına yardım edemem.
manatwork

Mac OS X'teki manpage ^ W ^ W ^ W stat (1) 'i çıktı biçimini belirtmek için -f bayrağına sahip olun, örn.stat -f 'chmod %p "%N"'
gelraen

12

Sembolik olan sekizlik gösterime dönüştürmek için bir zamanlar :

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

Expanded:

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

Bu ls -l, bir dosyadaki çıkışından sekizlik sayıyı döndürür .

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

Ben çıkışları dpkg"izin" yüklü olarak geri ayarlamak için kullanılır . İzin verilen dizeyi hangi komutun ürettiğine bakmadan gerçek soruyu cevapladığınız için teşekkür ederiz.
HiTechHiTouch

3

Bu komut Mac'te sh altında

stat -f "%Lp %N" your_files

yalnızca sayısal izin istiyorsanız, yalnızca% Lp kullanın.

Örneğin:

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

700, chmod'da kullanılabilecek sayısal izin ve Masaüstü dosya adıdır.


2

OP'nin girişiminden esinlenerek Y sorusuna ( X sorusunu görmezden geliyor ) bir cevap :

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

Yukarıda birkaç bashisms içerir. Aşağıdaki sürüm POSIX uyumlu görünüyor:

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

Notlar:

  • LC_COLLATE=CBu nedenle, ASCII düzeni kullanılarak tedavi yazmak sıralama aralığı kalıplarına kabuk anlatır [a-e]eşdeğerdir [abcde]. Bazı yerel ayarlarda (örneğin, en_US), [a-e]eşdeğerdir [aAbBcCdDeE] (yani [abcdeABCDE]) veya belki de [abcdeABCD]- bkz . Bash durum ifadesi neden büyük / küçük harfe duyarlı değildir? )
  • İkinci versiyonda (POSIX uyumlu olan):

    • İlk caseifade yeniden yazılabilir:

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

      ama sanırım şimdi sahip olduğum şekil, bunun l farklı bir şekilde ele alınan mektup olduğunu görmeyi kolaylaştırıyor . Alternatif olarak, yeniden yazılabilir:

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

      çünkü r, w, x, s, ve thiç bir mod dize (dışındaki görünmelidir sadece harfleri l).

    • İkinci caseifade yeniden yazılabilir:

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

      mod bitlerini belirtmek için yalnızca harflerin geçerli olduğu kuralı uygulamak. (Buna karşılık, tam komut dosyasında daha özlü sürüm tembeldir ve -rw@rw#rw%eşdeğer olarak kabul edilir  rwSrwSrwT.) Alternatif olarak, yeniden yazılabilir:

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

      çünkü S, s, T, t, L, ve l(başka hiç bir mod dizede görünmelidir tek harfler r, wve x).

Kullanımı:

$ 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

Ve evet, echobaşlayabilecek metinlerle birlikte kullanmamanın daha iyi olacağını biliyorum -; Kullanım örneğini sorudan kopyalamak istedim. Açıkçası, bunun 0. karakteri (yani, baştaki d/ b/ c/ -/ l/ p/ s/ D) ve 10. ( +/ ./ @) yok saydığını unutmayın . O, sağlayıcılardan varsayar lstanımlamak asla r/ Rveya w/ W(bunlar, onlar gerektiğini yaparsanız ve geçerli karakter olarak üçüncü, altıncı veya dokuzuncu pozisyonda sopalarla dövüldü ).


Ayrıca, sadece / var altında tüm dosyaların varsayılan grup / kullanıcı sahipliğini geri yükleme altında cas tarafından aşağıdaki kodu buldum :

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

Bu kodu test ettim (ama iyice değil) ve tanımadığı lveya Laltıncı pozisyonda olduğu dışında işe yarıyor gibi görünüyor . Bununla birlikte, bu cevap basitlik ve netlik açısından daha üstün olsa da, benimki aslında daha kısadır (yalnızca döngü içindeki kodu sayar; -rwxrwxrwxyorumları saymadan, tek bir dizeyi işleyen kod ) ve daha da kısa yapılabilir değiştirerek ile .if condition; then …condition && …


Tabii ki, çıktısını ayrıştırmamalısınızls .


@ StéphaneChazelas: Tamam, dedim #!/bin/shve sonra birkaç bashisms kullandım. Hata. Ama bir çift kaçırdın: ve POSIX gibi görünmüyor (Standart hiç bahsetmiyor ve sincap ve ve ). Tersine, ben vermedi kullanmak ; sadece görünen cas ı ‘ın cevabı, alıntılanan dan burada . Ayrıca, benim cevap kolu 'l' ve 'L' yapar ve ben zaten cas cevabı yok gerçeğini işaret etti. $(( variable++ ))$(( number ** number ))**++-- [[…]]
Scott

L / L için üzgünüm [[, çok hızlı okudum. Evet, - ve ++ POSIX değildir. POSIX, mermilerin bunları uygulamasına izin verir, yani $((- -a))bir çift olumsuzlama istiyorsanız yazmak zorundasınız, $((--a))bir azaltma işlemi için kullanabileceğinizden değil .
Stéphane Chazelas

Bunun seqbir POSIX komutu olmadığını unutmayın . İfadeyi önlemek için $ {var #?} Operatörünü kullanabilirsiniz. LC_COLLATE,
LC_ALL'ı

@ StéphaneChazelas: Tamam, şimdi cas'un cevabından bahsediyorsun, değil mi? Sekizli sayıya benzeyen bir dize oluşturmak için ondalık aritmetik kullanma "tembel" yaklaşımını kullanıyor. Tüm adım değerlerinin (4000, 2000, 1000, 400, 200, 100, 40, 20 ve 10) ondalık sayı olduğunu unutmayın. Ancak, 8'veya 9' olmadığı 7ve herhangi bir ondalık pozisyondan daha fazlasını elde etmenin bir yolu olmadığından , charade'i çekebilir. …………………… (Bu yorum, ortadan kaybolan Stéphane Chazelas yorumuna verilen bir yanıttır.)
Scott

Evet, bunu daha sonra fark ettim, bu yüzden yorumu sildim.
Stéphane Chazelas


0

Bir alternatif, izinleri kaydetmek istiyorsanız, daha sonra veya farklı bir dosyada setfacl/getfaclgeri yüklemek için kullanmaktır ve ayrıca (POSIX-taslak) ACL'lerini bonus olarak geri yükler.

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

(Solaris'te, -fyerine kullanın -M).

Bununla birlikte, bazı BSD'lerde mevcut olmalarına rağmen, ACL'lerin chmodyalnızca manipüle edildiği Apple OS / X'de değildirler .


0

Mac OS X'te (10.6.8) kullanmanız gerekir stat -f format(çünkü aslında NetBSD / FreeBSD'dir 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"

Ürettiği sembolik izin dizgisini ls -lsekizlik (yalnızca kabuk yerleşiklerini kullanarak) olarak çevirmek için bakınız: showperm.bash .

# from: showperm.bash
# usage: showperm modestring
#
# example: showperm '-rwsr-x--x'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.