スクリプトにはいくつか問題があります。深刻なものもあれば、そうでないものもあります。
まず、深刻な問題。
教祖が示唆したように、角括弧を使用して条件を囲む必要がありますif
。これはif
、条件の出力をテストするだけで、実際の文字列比較を実行しないためです。伝統的に、 と呼ばれるプログラム/bin/test
がそれを/bin/[
処理していました。最近では、その機能はシェルに組み込まれていますが、/bin/sh
それでも別のプログラムであるかのように動作します。
実際、条件に角括弧を使用しないif
場合でも興味深いことができます。たとえば、非常に一般的です。このコマンドは出力を発行せず、 によって検出された「成功」または「失敗」を返すだけです。if grep -q 'RE' /path/to/file; then
grep -q
if
2 番目の深刻な問題は、真である場合とそうでない場合があるステータスをエコーしているということです。私はこれを深刻な問題と呼んでいます。というのは、ログ メッセージが誤った主張をするべきではないからです。内のファイルのパーミッションが間違っている場合$1
、またはファイル名にスペースが含まれている場合、mv
コマンドは失敗しますが、失敗しなかったことを示すメッセージが表示されます。これについては後で詳しく説明します。
次に、深刻度の低い問題です。
これらは主にスタイルと最適化に関するものです。
まず、read
ほとんどのプラットフォームには-p
、プロンプトを指定できるオプションが含まれています。echo
これを使用すると、コマンドを含める必要はありません。
if
第二に、インデントにより、構造が何をラップしているかがわかりにくくなります。これは、この小さなプログラムでは大きな問題ではありませんが、成長するにつれて、一貫した標準に従うことが本当に必要になります。
case
第 3 に、の代わりにステートメントを使用すると、このような多肢選択問題でより柔軟に対応できる可能性がありif
ます。
結局のところ、このスクリプトの書き方は次のとおりです。
#!/bin/sh
if [ "$1" = "-y" ]; then
ans=y
shift
elif [ -t 0 ]; then
read -p "Are you sure you want to delete '$1' (y/N) ? " ans
fi
case "$ans" in
Y*|y*)
retval=0
if [ -z "$1" ]; then
retval=64
echo "ERROR: you didn't specify a filename." >&2
if [ ! -f "$1" ]; then
retval=66
echo "ERROR: file '$1' not found!" >&2
elif mv "$1" /home/parallels/dustbin/; then
echo "File '$1' has been deleted" >&2
else
retval=$?
echo "ERROR: file '$1' could not be deleted!" >&2
fi
;;
*)
echo "ABORT: file '$1' has not been deleted" >&2
retval=4
;;
esac
exit $retval
上記以外に、このコード スニペットには次のようなものがあります。
[ "$1" = "-y" ]
- ユーザーが-y
オプションを指定すると、質問に「はい」と答えたかのように動作します。
[ -t 0 ]
- これは、対話型端末を使用しているかどうかをテストします。もしそうなら、で質問するのは理にかなっていますread
。
Y*|y*)
- case ステートメントでは、大文字または小文字の「y」で始まるすべての文字列に一致します。したがって、有効な肯定応答は、「Y」、「はい」、「黄色」などになります。
[ ! -f "$1" ]
- これは、ファイルが存在するかどうかをテストします。シェルで利用可能なさまざまなテストを表示することができman test
ます。man sh
(-f
あなたにとって最も適切ではないかもしれません。)
>&2
- 行末で、その出力を「標準出力」ではなく「標準エラー」に送信します。これにより、出力がパイプや cron などによってどのように処理されるかが変更されます。エラーとログ データは多くの場合、stderr に送信されるため、stdout はプログラムの実際の出力専用になります。
mv "$1" ...
- ファイル名は引用符で囲みます。これにより、ファイル名にスペースなどの特殊文字が含まれている場合に保護されます。
$retval
- この値は、 内の最も近いアイテムの最良の推測に基づいていますman sysexits
。
retval=$?
- これは、最後に実行されたコマンドの終了ステータスです。この場合、これはmv
の終了ステータスを変数$retval
に割り当てていることを意味します。これにより、mv
失敗した場合、関係する限り、スクリプト全体が失敗の理由を報告しmv
ます。