แปลงรูปแบบเอาต์พุต ls -l เป็นรูปแบบ chmod


17

ว่าฉันมีผลลัพธ์ต่อไปนี้จากls -l:

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

ฉันจะแปลงเป็นรูปแบบที่ใช้โดยอัตโนมัติได้chmodอย่างไร

ตัวอย่างเช่น:

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

ฉันใช้ OS X 10.8.3


2
statมากง่ายขึ้นด้วย คุณมีหรือไม่ (มันเป็นเครื่องมือ GNU ซึ่งส่วนใหญ่มีอยู่บน Linux ไม่ใช่ใน Unix)
manatwork

@manatwork ให้stat foo 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มัน
Tyilo

คำตอบ:


24

บางระบบมีคำสั่งให้แสดงการอนุญาตของไฟล์เป็นตัวเลข แต่น่าเสียดายที่ไม่มีการพกพา

zshมีbuiltin stat(aka zstat) ในstatโมดูล:

zmodload zsh/stat
stat -H s some-file

จากนั้นโหมดmodeอยู่ใน$s[mode]แต่เป็นโหมดนั่นคือชนิด + perms

หากคุณต้องการสิทธิ์ที่แสดงออกเป็นฐานแปดคุณต้อง:

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

BSD (รวมถึงApple OS / X ) มีstatคำสั่งด้วย

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

GNU find (จากหลังสุดเท่าที่ 1990 และอาจมาก่อน) สามารถพิมพ์การอนุญาตเป็นฐานแปด:

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

ในภายหลัง (2001 ยาวหลังzsh stat(1997) แต่ก่อน BSD stat(2002)) statคำสั่งGNU ถูกนำมาใช้กับไวยากรณ์ที่แตกต่างอีกครั้ง:

stat -c %a some-file

นานก่อนหน้านั้น IRIX มีstatคำสั่ง (มีอยู่แล้วในIRIX 5.3ในปี 1994) ด้วยไวยากรณ์อื่น:

stat -qp some-file

อีกครั้งเมื่อไม่มีคำสั่งมาตรฐานทางออกที่ดีที่สุดสำหรับการพกพาคือการใช้perl:

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

15

คุณสามารถขอให้ GNU statส่งออกการอนุญาตในรูปแบบฐานแปดโดยใช้-cตัวเลือก จาก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

ดังนั้นในกรณีของคุณ:

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

หรือคุณสามารถทำให้เป็นอัตโนมัติโดยการจัดรูปแบบstatเอาต์พุตเป็นคำสั่งที่ถูกต้อง:

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

โซลูชันด้านบนจะทำงานกับไฟล์หลายไฟล์ได้หากใช้ไวด์การ์ด:

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

จะทำงานอย่างถูกต้องกับชื่อไฟล์ที่มีอักขระช่องว่าง แต่จะล้มเหลวในชื่อไฟล์ที่มีเครื่องหมายคำพูดเดี่ยว


2
ฉันstatไม่มี-cตัวเลือก ฉันใช้ OS X 10.8.3
Tyilo

ขอบคุณสำหรับข้อมูล @Tyilo และขออภัยฉันไม่สามารถช่วยด้วยเครื่องมือของ OS X
จัดการ

ลองอ่าน manpage ^ W ^ W ^ W stat (1) บน Mac OS X มีแฟstat -f 'chmod %p "%N"'
ล็ก

11

ในการแปลงจากสัญลักษณ์เป็นสัญกรณ์ฐานแปดฉันเคยคิดขึ้นมาว่า :

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

ขยาย:

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

ที่ส่งคืนหมายเลขฐานแปดจากเอาต์พุตของls -lหนึ่งไฟล์

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

ฉันใช้สิ่งนี้ในผลลัพธ์ของdpkgการตั้งค่าการอนุญาตกลับเป็น "พร้อมติดตั้ง" ขอบคุณสำหรับการตอบคำถามตามตัวอักษรโดยไม่คำนึงถึงคำสั่งที่สร้างสตริงการอนุญาต
HiTechHiTouch

3

คำสั่งนี้บน Mac ภายใต้ sh

stat -f "%Lp %N" your_files

หากคุณต้องการได้รับอนุญาตเป็นตัวเลขให้ใช้% Lp เท่านั้น

ตัวอย่างเช่น:

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

700 เป็นสิทธิ์ตัวเลขที่สามารถใช้ใน chmod และ Desktop เป็นชื่อไฟล์


2

ต่อไปนี้เป็นคำตอบสำหรับคำถามY (ละเว้นคำถามX ) ซึ่งได้รับแรงบันดาลใจจากความพยายามของ 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

ด้านบนมี bashisms ไม่กี่ ดูเหมือนว่ารุ่นต่อไปนี้จะสอดคล้องกับ 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

หมายเหตุ:

  • LC_COLLATE=Cบอกเปลือกตัวอักษรรักษารูปแบบช่วงลำดับการใช้คำสั่ง ASCII เพื่อให้เทียบเท่ากับ[a-e] [abcde]ในบางแห่ง (เช่น en_US) [a-e]เทียบเท่ากับ[aAbBcCdDeE] (เช่น, [abcdeABCDE]) หรือบางที[abcdeABCD]- ดูทำไมคำสั่ง bash case ไม่คำนึงถึงขนาดตัวพิมพ์ ... )
  • ในเวอร์ชันที่สอง (POSIX ที่เข้ากันได้):

    • caseคำสั่งแรกสามารถเขียนใหม่ได้:

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

      แต่ฉันคิดว่าวิธีที่ฉันมีตอนนี้ทำให้ง่ายขึ้นที่จะเห็นว่าl เป็นจดหมายที่ถูกจัดการแตกต่างกัน อีกวิธีหนึ่งก็สามารถเขียนใหม่:

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

      ตั้งแต่r, w, x, sและtมีตัวอักษรตัวเดียวที่เคยควรปรากฏในสตริงโหมด (นอกเหนือl)

    • caseคำสั่งที่สองสามารถเขียนใหม่ได้:

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

      เพื่อบังคับใช้กฎว่าเฉพาะตัวอักษรเท่านั้นที่ถูกต้องสำหรับการระบุบิตโหมด (ตรงกันข้ามเวอร์ชันที่สั้นกว่าของสคริปต์แบบเต็มจะขี้เกียจและจะยอมรับได้-rw@rw#rw%เทียบเท่า  rwSrwSrwT) อีกทางหนึ่งก็อาจเขียนใหม่ได้:

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

      ตั้งแต่S, s, T, t, Lและlมีตัวอักษรตัวเดียวที่เคยควรปรากฏในสตริงโหมด (นอกเหนือจากr, wและx)

การใช้งาน:

$ 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

และใช่ฉันรู้ว่ามันจะดีกว่าที่จะไม่ใช้echoกับข้อความที่อาจเริ่มต้นด้วย-; ฉันแค่ต้องการคัดลอกตัวอย่างการใช้งานจากคำถาม โปรดทราบว่าสิ่งนี้จะละเว้นอักขระที่ 0 (เช่นการนำหน้าd/ b/ c/ -/ l/ p/ s/ D) และอันดับที่ 10 ( +/ ./ @) ถือว่าผู้ดูแลของlsจะไม่กำหนด r/ Rหรือw/ Wเป็นอักขระที่ถูกต้องในตำแหน่งที่สาม, หกหรือเก้า (และถ้าพวกเขาทำพวกเขาควรจะพ่ายแพ้ด้วยไม้ )


นอกจากนี้ฉันเพิ่งพบรหัสต่อไปนี้โดยcasภายใต้ วิธีการคืนค่ากลุ่ม / เจ้าของผู้ใช้เริ่มต้นของไฟล์ทั้งหมดภายใต้ / 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 ))

ฉันได้ทดสอบรหัสนี้ (แต่ไม่ละเอียด) และดูเหมือนว่าจะทำงานได้ยกเว้นว่ามันไม่รู้จักlหรือLอยู่ในตำแหน่งที่หก แม้ว่าในขณะที่คำตอบนี้เหนือกว่าในแง่ของความเรียบง่ายและความชัดเจนเหมืองของฉันจะสั้นกว่าจริง ๆ (นับเฉพาะโค้ดภายในลูปเท่านั้นโค้ดที่จัดการกับ-rwxrwxrwxสตริงเดี่ยวไม่นับความคิดเห็น) และอาจทำให้สั้นลงได้ โดยการแทนที่ด้วย if condition; then …condition && …


แน่นอนคุณไม่ควรแยกการส่งออกของls


@ StéphaneChazelas: ตกลงฉันพูด#!/bin/shแล้วใช้ bashisms ไม่กี่ อุ่ย แต่คุณพลาดคู่: และดูเหมือนจะไม่ POSIX อย่างใดอย่างหนึ่ง (มาตรฐานไม่ได้พูดถึงเลยและกระรอกและ) ตรงกันข้ามผมไม่ได้ใช้ ; ที่ปรากฏขึ้นเฉพาะในCAS ‘s คำตอบที่ผมยกมาจากที่นี่ นอกจากนี้คำตอบของฉันจะจัดการ 'l' และ 'L' และฉันได้ชี้ให้เห็นแล้วว่าคำตอบของ cas ไม่ได้ $(( variable++ ))$(( number ** number ))**++-- [[…]]
สกอตต์

ขออภัยเกี่ยวกับ l / L [[ฉันอ่านเร็วเกินไป ใช่ - และ ++ ไม่ใช่ POSIX POSIX อนุญาตให้เชลล์นำไปใช้งานซึ่งหมายความว่าคุณต้องเขียน$((- -a))หากคุณต้องการลบล้างสองเท่าไม่ใช่ว่าคุณอาจใช้$((--a))เพื่อหมายถึงการลดค่าลง
Stéphane Chazelas

โปรดทราบว่าseqไม่ใช่คำสั่ง POSIX คุณอาจใช้โอเปอเรเตอร์ $ {var #?} เพื่อหลีกเลี่ยงการแสดงตัวอย่าง ไม่ว่า LC_COLLATE จะไม่แทนที่ LC_ALL
Stéphane Chazelas

@ StéphaneChazelas: ตกลงคุณกำลังพูดถึงคำตอบของ cas อีกครั้งใช่ไหม? เขาใช้วิธี "ขี้เกียจ" ในการใช้เลขคณิตทศนิยมเพื่อสร้างสตริงที่ดูเหมือนเลขฐานแปด โปรดทราบว่าค่าขั้นตอนของเขาทั้งหมด (4000, 2000, 1,000, 400, 200, 100, 40, 20 และ 10) เป็นตัวเลขทศนิยม แต่เนื่องจากไม่มี8หรือ9ไม่มีและไม่มีทางที่จะได้รับมากกว่า7ตำแหน่งทศนิยมใด ๆ เขาสามารถดึงปริศนาได้ ……………………… (ความคิดเห็นนี้เป็นการตอบสนองต่อความคิดเห็นของStéphane Chazelas ที่หายไป)
Scott

ใช่ฉันรู้ว่าในภายหลังซึ่งเป็นสาเหตุที่ฉันลบความคิดเห็น
Stéphane Chazelas

1

หากเป้าหมายของคุณคือการรับอนุญาตจากไฟล์หนึ่งและมอบให้กับไฟล์อื่นเช่นกัน GNU chmodมีตัวเลือก "อ้างอิง" สำหรับสิ่งนั้น


สหกรณ์กล่าวถึงเขาอยู่ในแอปเปิ้ล OS / X ดังนั้นchmodจะไม่เป็น GNU chmodมี
Stéphane Chazelas

ใช่ฉันเห็นความคิดเห็นในคำตอบอื่น ๆ ที่พวกเขาพูดแพลตฟอร์มของพวกเขา เหมืองแร่ไม่ได้เป็นเพียงคนเดียวที่กล่าวขวัญ GNU และแม้ว่าคุณจะได้รับ GNU สาธารณูปโภคบน Mac OS X
Bratchley

0

อีกทางเลือกหนึ่งถ้าคุณต้องการบันทึกการอนุญาตเก็บกู้คืนในภายหลังหรือใช้ไฟล์setfacl/getfaclอื่นและมันจะกู้คืน (POSIX-draft) ACLs เป็นโบนัส

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

(บน Solaris ให้ใช้-fแทน-M)

อย่างไรก็ตามแม้ว่าจะมีใน BSD บางตัว แต่ก็ไม่ได้อยู่ใน Apple OS / X ที่มีการจัดการ ACL ด้วยchmodเท่านั้น


0

บน Mac OS X (10.6.8) คุณต้องใช้stat -f format(เพราะจริง ๆ แล้วเป็น 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"

เพียงแค่แปลสตริงได้รับอนุญาตเป็นสัญลักษณ์ที่ผลิตโดยls -lเข้าไปในฐานแปด (ใช้เพียง builtins เชลล์) โปรดดูที่: showperm.bash

# from: showperm.bash
# usage: showperm modestring
#
# example: showperm '-rwsr-x--x'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.