わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

cshでother readable判定

あるcshシェルスクリプトの中で,ファイル(とりあえずabc.def)がother readableであるかを判定する必要に迫られました.
other readableとは,他グループのユーザから読めるパーミッションになっているか,です.
あるいはls -lを実行して,左に「lrwxrwxrwx」とか「-rw-r--r--」とか出てくるなら,左から3番目が「r」となっていればother readable,「-」ならそうでない,と言えます.
さて,なぜ今時cshなのかというと,何人かに実行してもらうスクリプトなのです.そしてその環境でのデフォルトのシェルが,bashではなくcshとなっています.
昨日終わったので,もう少しだけ詳細を書くと,利用してもらう人へは「作業の前に source ~takehikom/script を実行してください」という指示をしました.そして ~takehikom/script には,このように書いておきます:

source (~takehikomのフルパス)/script.$0

その上で,スクリプトファイル ~takehikom/script.bash と ~takehikom/script.csh を別々に作っておきます.ただしいずれのスクリプトファイルにも,「#!」から始まるshebangは設けません.というのも,source ~takehikom/script を実行すると,あるディレクトリがなければ作って,そこに移動する(そしてそのディレクトリ上で,コマンド実行などをしてもらう)という処理が,入っているからです.sourceなしで,シェルスクリプトとして実行した場合には,任意のディレクトリに移動できても,スクリプト終了後には,実行前のディレクトリに戻ってしまい,今回の状況には望ましくありません.
さて本題の,other readable発見方法です.試行錯誤の末,こんなコードになりました.

set file = 'abc.def'
if ( `echo $file` != `find $file -type f -perm -4 |& cat` ) then
    echo "${file}のパーミッションが不適切です"
endif

findコマンドでエラーメッセージを出す可能性も考慮して,bashでの「2>&1」に相当する処理を入れたいのですが,「|&」で共通化してパイプに通し,その先のコマンドを,もっとも単純なフィルタと言われるcatにしました.
肝心のif文.理想は,適切なfindコマンドを実行して,該当ファイルが条件を満たしているなら真(then以下を実行),そうでなければ偽(else以下を実行),とすることです.
なのですが,findコマンドは,該当ファイルが0件のときでも1件以上あっても,終了ステータスが0になるので,使えません.
それと,cshのif文として,コマンドを実行して終了ステータスが0か否かという判定は,どうも書けないようです*1
そこで,該当ファイルが条件を満たしていれば,そのファイル名のみを,そうでなければ空文字列を出力させ,それを,ファイル名と比較することにしました.上は,その方針でうまくいったコードですが,しばらくの間は,以下のように書いて,常に真(左右の文字列が一致しない)となって苦労しました.

if ( $file != `find $file -type f -perm -4 |& cat` ) then

もしかして,「`...`」で末尾の改行を取り除いてくれないのかな,と考えて,右辺の改行除去よりも,左辺に改行をつけるほうが単純なので,「`echo $file`」に置き換えると,成功でした.
同じ判定をするbash版です.「`...`」で最後の改行文字を除去するため,「"`...`"」とする必要がありました.

file='abc.def'
if [ $file != "`find $file -type f -perm -4 2>&1`" ];
    then
    echo "${file}のパーミッションが不適切です"
fi

ディレクトリのother readable判定も書いておきます.「r-x」または「rwx」がほしいので,パーミッションの数値は「5」です.

# csh版
dir = $HOME/20090730
if ( `echo $dir` != `find $dir -type d -perm -5 |& head -n 1` ) then
    echo "${dir}のパーミッションが不適切です"
endif
# bash版
dir=$HOME/20090730
if [ $DIR != "`find $DIR -type d -perm -5 2>&1 | head -n 1`" ];
    then
    echo "${dir}のパーミッションが不適切です"
fi

(翌日追記)
参考にさせていただいたページ.

*1:ifを使わず,「条件判定コマンド && 正常終了のときに実行するコマンド」「条件判定コマンド || 異常終了のときに実行するコマンド」という書き方はありますが,あとで見直したときに分かりにくいし,正常終了・異常終了で別々に実行するコマンドというのが自然な形で書けない,という問題があります.