Chuyển đổi định dạng đầu ra ls -l sang định dạng chmod


17

Nói rằng tôi có đầu ra sau từ ls -l:

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

Làm cách nào tôi có thể tự động chuyển đổi định dạng này sang định dạng được sử dụng chmod?

Ví dụ:

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

Tôi đang sử dụng OS X 10.8.3.


2
Dễ dàng hơn nhiều với stat. Bạn có không? (Đây là một công cụ GNU, vì vậy hầu hết có sẵn trên Linux, không phải trên Unix.)
manatwork

@manatwork stat foocho 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. Tôi không thấy 755trong đó.
Tyilo

Câu trả lời:


24

Một số hệ thống có các lệnh để hiển thị các quyền của một tệp dưới dạng số, nhưng thật không may, không có gì có thể mang theo được.

zshcó một stat(aka zstat) dựng sẵn trong statmô-đun:

zmodload zsh/stat
stat -H s some-file

Sau đó, modetrong $s[mode]nhưng là chế độ, đó là loại + perms.

Nếu bạn muốn các quyền được thể hiện bằng số bát phân, bạn cần:

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

BSD (bao gồm cả Apple OS / X ) cũng có statlệnh.

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

GNU find (từ năm 1990 trở về trước và có thể trước đó) có thể in các quyền dưới dạng bát phân:

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

Sau đó (2001, rất lâu sau zsh stat(1997) nhưng trước BSD stat(2002)), một statlệnh GNU được giới thiệu với một cú pháp khác:

stat -c %a some-file

Rất lâu trước đó, IRIX đã có một statlệnh (đã có trong IRIX 5.3 năm 1994) với một cú pháp khác:

stat -qp some-file

Một lần nữa, khi không có lệnh tiêu chuẩn, đặt cược tốt nhất cho tính di động là sử dụng perl:

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

15

Bạn có thể yêu cầu GNU statxuất các quyền ở định dạng bát phân bằng cách sử dụng -ctùy chọn. Từ 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

Vì vậy, trong trường hợp của bạn:

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

Hoặc thậm chí bạn có thể tự động hóa nó bằng cách định dạng statđầu ra dưới dạng lệnh hợp lệ:

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

Giải pháp trên cũng sẽ hoạt động cho nhiều tệp nếu sử dụng ký tự đại diện:

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

Sẽ hoạt động chính xác với tên tệp chứa ký tự khoảng trắng, nhưng sẽ thất bại đối với tên tệp chứa dấu ngoặc đơn.


2
Tôi statkhông có -clựa chọn. Tôi đang sử dụng OS X 10.8.3.
Tyilo

Cảm ơn thông tin, @Tyilo. Và xin lỗi, tôi không thể giúp với các công cụ của OS X.
manatwork

Hãy thử đọc manpage ^ W ^ W ^ W stat (1) trên Mac OS X có cờ -f để xác định định dạng đầu ra, ví dụ nhưstat -f 'chmod %p "%N"'
gelraen

11

Để chuyển đổi từ ký hiệu tượng trưng sang bát phân, tôi đã từng nghĩ ra :

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

Mở rộng:

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

Điều đó trả về số bát phân từ đầu ra của ls -lmột tệp.

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

Tôi đã sử dụng điều này trên đầu ra của dpkgđể đặt quyền trở lại "như đã cài đặt". Cảm ơn bạn đã trả lời câu hỏi theo nghĩa đen mà không quan tâm đến lệnh nào đã tạo ra chuỗi quyền.
HiTechHiTouch

3

Lệnh này trên Mac theo sh

stat -f "%Lp %N" your_files

nếu bạn chỉ muốn quyền số, chỉ sử dụng% Lp.

ví dụ:

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

700 là quyền số có thể được sử dụng trong chmod và Desktop là tên tệp.


2

Đây là câu trả lời cho câu hỏi Y (bỏ qua câu hỏi X ), lấy cảm hứng từ nỗ lực của 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

Ở trên có chứa một vài bashism. Phiên bản sau đây có vẻ tuân thủ 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

Ghi chú:

  • Cái LC_COLLATE=Cvỏ nói để xử lý các mẫu phạm vi chuỗi ký tự như sử dụng thứ tự ASCII, do đó [a-e]tương đương với [abcde]. Ở một số địa phương (ví dụ: en_US), [a-e]tương đương với [aAbBcCdDeE] (nghĩa là [abcdeABCDE]) hoặc có lẽ [abcdeABCD]- xem Tại sao câu lệnh bash không phân biệt chữ hoa chữ thường? )
  • Trong phiên bản thứ hai (phiên bản tuân thủ POSIX):

    • caseTuyên bố đầu tiên có thể được viết lại:

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

      nhưng tôi nghĩ rằng cách tôi có bây giờ giúp dễ dàng nhận thấy đó l là bức thư được xử lý khác nhau. Ngoài ra, nó có thể được viết lại:

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

      từ r, w, x, s, và tlà các chữ cái duy nhất mà bao giờ sẽ xuất hiện trong một chuỗi chế độ (trừ l).

    • caseTuyên bố thứ hai có thể được viết lại:

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

      để thực thi quy tắc chỉ các chữ cái là hợp lệ để chỉ định các bit chế độ. (Ngược lại, phiên bản ngắn gọn hơn trong toàn bộ kịch bản là lười biếng và sẽ chấp nhận -rw@rw#rw%tương đương với  rwSrwSrwT.) Ngoài ra, nó có thể được viết lại:

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

      từ S, s, T, t, L, và llà các chữ cái duy nhất mà bao giờ sẽ xuất hiện trong một chuỗi chế độ (trừ r, wx).

Sử dụng:

$ 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

Và, vâng, tôi biết tốt hơn là không sử dụng echovới văn bản có thể bắt đầu bằng -; Tôi chỉ muốn sao chép ví dụ sử dụng từ câu hỏi. Lưu ý, rõ ràng, điều này bỏ qua ký tự thứ 0 (nghĩa là hàng đầu d/ b/ c/ -/ l/ p/ s/ D) và thứ 10 ( +/ ./ @). Nó giả định rằng những người duy trì lssẽ không bao giờ định nghĩa r/ Rhoặc w/ Wlà các ký tự hợp lệ ở vị trí thứ ba, thứ sáu hoặc thứ chín (và, nếu họ làm như vậy, họ nên bị đánh bằng gậy ).


Ngoài ra, tôi chỉ tìm thấy đoạn mã sau, theo cas , trong Cách khôi phục quyền sở hữu nhóm / người dùng mặc định của tất cả các tệp trong / 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 ))

Tôi đã kiểm tra mã này (nhưng không kỹ lưỡng) và nó dường như hoạt động, ngoại trừ thực tế là nó không nhận ra lhoặc Lở vị trí thứ sáu. Mặc dù vậy, lưu ý rằng mặc dù câu trả lời này vượt trội về tính đơn giản và rõ ràng, nhưng câu trả lời của tôi thực sự ngắn hơn (chỉ tính mã bên trong vòng lặp; mã xử lý một -rwxrwxrwxchuỗi, không tính bình luận) và nó có thể được rút ngắn hơn bằng cách thay thế bằng .if condition; then …condition && …


Tất nhiên, bạn không nên phân tích đầu ra củals .


@ StéphaneChazelas: OK, tôi đã nói #!/bin/shvà sau đó sử dụng một vài bashism. Giáo sư. Nhưng bạn đã bỏ lỡ một cặp vợ chồng: và dường như cũng không phải là POSIX (Tiêu chuẩn hoàn toàn không đề cập đến , và là vấn đề nghiêm trọng và ). Ngược lại, tôi đã không sử dụng ; chỉ xuất hiện trong câu trả lời của cas , mà tôi đã trích dẫn từ đây . Ngoài ra, câu trả lời của tôi xử lý 'l' và 'L', và tôi đã chỉ ra thực tế rằng câu trả lời của cas không. $(( variable++ ))$(( number ** number ))**++-- [[…]]
Scott

Xin lỗi về l / L [[, tôi đọc quá nhanh. Có, - và ++ không phải là POSIX. POSIX cho phép shell thực hiện chúng, điều đó có nghĩa là bạn phải viết $((- -a))nếu bạn muốn phủ định kép, không phải là bạn có thể sử dụng $((--a))để có nghĩa là một hoạt động giảm dần.
Stéphane Chazelas

Lưu ý rằng đó seqkhông phải là lệnh POSIX. Bạn có thể sử dụng toán tử $ {var #?} Để tránh expr. Không phải LC_COLLATE sẽ không ghi đè LC_ALL
Stéphane Chazelas

@ StéphaneChazelas: OK, bây giờ bạn đang nói về câu trả lời của cas phải không? Anh ta sử dụng phương pháp "lười biếng" bằng cách sử dụng số học thập phân để xây dựng một chuỗi trông giống như một số bát phân. Lưu ý rằng tất cả các giá trị bước của anh ấy (4000, 2000, 1000, 400, 200, 100, 40, 20 và 10) là số thập phân. Nhưng, vì không có 8hoặc 9không có cách nào để có được nhiều hơn 7ở bất kỳ vị trí thập phân nào, anh ta có thể kéo theo trò chơi đố chữ. ... ... ... ... ... ... ... ... (Nhận xét này là một phản ứng với một lời nhận xét Stéphane Chazelas mà biến mất.)
Scott

Vâng, tôi nhận ra rằng sau đó, đó là lý do tại sao tôi xóa bình luận.
Stéphane Chazelas

1

Nếu mục tiêu của bạn là lấy quyền từ một tệp và cũng cung cấp chúng cho tệp khác, GNU chmodđã có tùy chọn "tham chiếu" cho điều đó .


OP đã đề cập rằng anh ta đã ở trên Apple OS / X, vì vậy chmodsẽ không có GNU chmodở đó.
Stéphane Chazelas

À đúng rồi, tôi đang xem bình luận về câu trả lời khác nơi họ nói nền tảng của họ. Của tôi không phải là người duy nhất đề cập đến GNU và bạn có thể nhận được Tiện ích GNU trên Mac OS X
Bratchley

0

Một cách khác, nếu bạn muốn lưu các quyền đi, để khôi phục chúng sau này hoặc trên một tệp khác là sử dụng setfacl/getfacl, và nó cũng sẽ khôi phục ACL (bản nháp POSIX) như một phần thưởng.

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

(trên Solaris, sử dụng -fthay vì -M).

Tuy nhiên, mặc dù chúng có sẵn trên một số BSD, nhưng chúng không có trên Apple OS / X nơi ACL chỉ được thao tác chmod.


0

Trên Mac OS X (10.6.8), bạn phải sử dụng stat -f format(vì thực tế nó là 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"

Để chỉ dịch một chuỗi cấp phép tượng trưng được tạo bởi ls -lthành bát phân (chỉ sử dụng các nội trang shell), hãy xem: showperm.bash .

# from: showperm.bash
# usage: showperm modestring
#
# example: showperm '-rwsr-x--x'
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.