3

私はシェルスクリプトを初めて使用します。スクリプトは問題ないように見えますが、そのフローの制御に問題があります。誰かが私が犯したばかげた間違いを指摘してもらえますか?

#! /bin/sh

echo "Are you sure youx want to delete $1? Answer y or n"
read ans
echo $ans
if $ans = "y"|"Y"
then
    mv $1 /home/parallels/dustbin
    echo "File $1 has been deleted"
else echo "File $1 has not been deleted"
fi
4

4 に答える 4

1

スクリプトにはいくつか問題があります。深刻なものもあれば、そうでないものもあります。

まず、深刻な問題。

教祖が示唆したように、角括弧を使用して条件を囲む必要がありますif。これはif、条件の出力をテストするだけで、実際の文字列比較を実行しないためです。伝統的に、 と呼ばれるプログラム/bin/testがそれを/bin/[処理していました。最近では、その機能はシェルに組み込まれていますが、/bin/shそれでも別のプログラムであるかのように動作します。

実際、条件に角括弧を使用しないif場合でも興味深いことができます。たとえば、非常に一般的です。このコマンドは出力を発行せず、 によって検出された「成功」または「失敗」を返すだけです。if grep -q 'RE' /path/to/file; thengrep -qif

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ます。
于 2012-12-04T05:39:59.833 に答える
1

if 条件を次のようにします。

if [ "$ans" = "y" -o "$ans" = "Y" ]
于 2012-12-03T12:06:19.523 に答える
0

また、ユーザーの応答をいずれかのケースに変換して、次のようにそれぞれのケースを確認することもできます。

read ans
ans=${ans,,}  # make 'ans' lowercase, or use ${ans^^} for making it uppercase
if [ "$ans" = "y" ]
then
   ....
fi
于 2012-12-03T15:48:38.077 に答える
0

以下は、エラー処理を含む完全なコードです

#!/bin/sh

echo "Are you sure you want to delete $1? Answer y or n"
read ans
echo $ans

if [ $ans == "y" ] || [ $ans == "Y" ]
then
    if [ -f $1 ]
    then
           mv $1 /home/parallels/dustbin
           echo "File $1 has been deleted"         
    else
           echo " File $1 is not found"
    fi
else 
    echo "File $1 has not been deleted"
fi
于 2012-12-04T13:11:46.227 に答える