rw-r--r--などのファイルモードの文字列を、0644などの8進数に変換するシェルスクリプトのロジック例


備忘

AnsibleやChefなどによる構成やそのテスト時に、rw-r--r--などのファイルモードの文字列を0644などの8進数に変換する必要があった。

スクリプトロジックサンプル


MODE="rw-r--r--"

echo "0$(
  echo "ibase=2; obase=8; $( 
    echo "${MODE}" | sed -e 's/..\(.\)..\(.\)..\(.\)/\1\2\3/' -e 's/[-x]/0/g' -e 's/[^0]/1/g'
  )$(
    echo "${MODE}" | sed -e 's/[a-z]/1/g' -e 's/[^1]/0/g'
  )" | bc
)"


0644

MODE="rwsr-xr-T"

05754

sed -e 's/..\(.\)..\(.\)..\(.\)/\1\2\3/'

sStTなどの拡張部分処理の初段
3,6,9文字目を取り出す
rwsr-xr-T ならば sxT

sed -e 's/[-x]/0/g' -e 's/[^0]/1/g'

-やxは0に、それ以外は1に変換
sxT ならば 101

sed -e 's/[a-z]/1/g' -e 's/[^1]/0/g'

本来のrwx部分の処理
小文字アルファベットは1に、それ以外は0に変換
rwsr-xr-T ならば 111101100

echo "ibase=2; obase=8; $( ... )$( ... )" | bc

一つ目の...を実行したstdout文字列と二つ目の...を実行したstdout文字列をつなげて2進数として読み込み8進数で出力
なお、$( ... )は、stdout行末の改行コードなどを取り除く

echo "0$( ... )"

...を実行したstdout文字列の先頭に8進数であることを示す0を追加して出力

参考1: Linuxの場合、statコマンドでファイルのパーミッションを直接確認可能

$ stat -c %a /etc/hosts
644

参考2: AIXの場合、以下のソリューションが提供されている

上を参考にスクリプトを書くと以下の様な感じか。

/usr/bin/stat
#!/usr/bin/ksh
printf "$(
  echo "ibase=2; obase=8; $(
    /usr/bin/ls -l $@ | /usr/bin/awk '{
      a=substr($1,4,1)substr($1,7,1)substr($1,10,1); gsub("[-x]",0,a); gsub("[^0]",1,a);
      b=substr($1,2,9); gsub("[a-z]",1,b); gsub("[^1]",0,b); 
      print a b;
    }' 
  )" | bc
)    "
/usr/bin/ls -l $@