ls -l 출력 형식을 chmod 형식으로 변환

ls -l 출력 형식을 chmod 형식으로 변환

다음과 같은 출력이 있다고 가정해 보겠습니다 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을 사용하고 있습니다.

답변1

일부 시스템에는 파일 권한을 숫자로 표시하는 명령이 있지만 불행히도 이식 가능한 것은 없습니다.

zsh모듈에는 stat(일명) 내장 함수가 있습니다.zstatstat

zmodload zsh/stat
stat -H s some-file

그렇다면, mode안에 있는 것은 $s[mode]모드인데, 타입 + 퍼머입니다.

8진수로 권한을 얻으려면 다음이 필요합니다.

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

BSD(포함애플 OS/Xstat)에도 명령이 있습니다.

stat -f %Lp some-file

(아니요 L, 완료되었습니다.모델반환값(8진수로 표시)

GNU find(1990년, 아마도 그 이전)는 권한을 8진수로 인쇄할 수 있습니다.

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

나중에(2001년, zsh stat1997년 이후, BSD stat(2002) 이전) GNU stat명령은 다시 다른 구문을 도입했습니다.

stat -c %a some-file

이들보다 오래 전에 IRIX에는 이미 stat명령이 있었습니다(이미아이릭스 5.31994), 대체 구문을 사용합니다.

stat -qp some-file

마찬가지로 표준 명령이 없는 경우 이식성을 위한 최선의 옵션은 다음을 사용하는 것입니다 perl.

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

답변2

stat이 옵션을 사용하여 GNU에게 8진수 형식으로 권한을 출력하도록 요청할 수 있습니다 -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'" -- *

이는 공백 문자가 포함된 파일 이름에는 잘 작동하지만 작은따옴표가 포함된 파일 이름에는 실패합니다.

답변3

기호 표기법을 8진수 표기법으로 변환하려면일단 나타나면그리고:

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이는 파일 출력에서 ​​8진수를 반환합니다.

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

답변4

이것이 질문에 대한 답변입니다(소홀히 하다질문엑스), 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

위 내용에는 일부 공격적인 내용이 포함되어 있습니다. 다음 버전은 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 케이스 문이 대소문자를 구분하지 않는 이유는 무엇입니까...?)
  • 두 번째 버전(POSIX 호환 버전):

    • 첫 번째 case문은 다음과 같이 다시 작성할 수 있습니다.

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

      하지만 지금의 방식을 보면 그 l 편지가 다른 방식으로 처리되고 있다는 것을 더 쉽게 알 수 있다고 생각합니다. 또는 다음과 같이 다시 작성할 수 있습니다.

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

      왜냐하면 r, w, xst패턴 문자열에 나타나야 하는 유일한 문자( 제외)이기 때문입니다 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/ )와 10번째 문자( / / )를 무시한다는 점에 유의하십시오. 이는 유지관리자가 /or/를 세 번째, 여섯 번째 또는 아홉 번째 위치의 유효한 문자로 정의하지 않을 것이라고 가정합니다.sD+.@lsrRwW막대기로 구타당하다).


또한 방금 다음 코드를 찾았습니다.카스, 아래에 /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이 코드를 (완전히 테스트하지는 않았지만) 테스트했는데 인식되지 않거나 L6번째 위치에 있다는 사실을 제외하고는 작동하는 것 같습니다 . 하지만 이 답변은 단순성과 명확성 측면에서 우수하지만 실제로는 더 짧습니다.~에루프; 주석을 제외하고 단일 문자열을 처리하는 코드) -rwxrwxrwx로 대체하여 더 짧게 만들 수 있습니다.if condition; then …condition && …


물론이죠출력을 구문 분석하면 안 됩니다.ls.

관련 정보