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(付属Apple 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)より前)、GNUstatコマンドは再び別の構文を導入しました。

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

これが質問に対する答えですはい(無視する質問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

上記にはいくつかの積極的なコンテンツが含まれています。次のバージョンは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ケース文が大文字と小文字を区別しないのはなぜですか?)
  • 2番目のバージョン(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

    • 2番目の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あるからです(、および除く)。TtLlrwx

使用法:

$ 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 /を3番目、6番目、または9番目の位置の有効な文字として定義しないと仮定します。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

関連情報