Caseステートメントを使用してUNIXで詳細モードをオン/オフする方法

Caseステートメントを使用してUNIXで詳細モードをオン/オフする方法

getoptsを使用してシェルスクリプトファイルを生成しようとしています。このプログラムの目的は、プロジェクトからファイルを削除し、ごみ箱とも呼ばれる削除されたディレクトリに保存することです。私はこれをうまくやることができました。

また、getoptコマンド-i(対話型)を使用してCaseステートメントを渡し、ユーザーにファイルを削除するかどうかを尋ねる質問を促すこともできました。

これは、変数「ision」を生成し、Caseステートメントを有効にするときにtrueに設定することによって行われます。以下にコードを挿入しました。何度も試してみましたが、すべてが問題ないようですが、詳細なアクティビティ/モードを追加したいと思います。誰でも私を助けることができますか?

#!/bin/bash

while getopts ":i:v" option ;
do
case "$option" in
i) echo "interactive mode set"
ision=true;
break;;
v) echo "verbose mode"
vison=true;
break;;
esac
done
echo "this is the proof we need"

echo $@

shift $(($OPTIND-2))

echo $@

echo "this is working too"

if [ ! -e ~/deleted ]
then
mkdir ~/deleted
fi

echo "the echo file was made or just created"

if [ $# -eq 0 ]
then
echo "safe_rm missing operand"
exit
fi

echo "all workking on the western front"

for i in $@
do

if [ "$ision" == "true" ]
then
echo "do you want to remobve the file"
echo "variable test $i"
echo "yes or no"
read -p "Enter " answer
if [ "$answer" == "no" ]
then
continue;
fi
fi

if [ ! -f $i ]
then
echo "no such file or directory"
exit
fi
        if [ $i == safe_rm ]
        then

        echo "cant remove safe_rm"
        continue
        fi

        if [ $i == safe_rm_restore ]
        then
        continue
        echo "cant remove safe_rm_restore"

        fi

inode=$(ls -i $i | cut -c -6 )
echo "the inode is $inode "
pathname=$(dirname $i)
if [ $pathname == "." ]
then
pathname=$(pwd)
echo $pathname
fi
basename=$(basename $i)
path=$basename"_"$inode":"$pathname"/"$basename

echo $path

if [ ! -f .restoreinfo ]
then
touch .restoreinfo
fi


echo $path >> .restoreinfo
mv $i ~/deleted/

done

答え1

ここでは、コマンドラインの解析に焦点を当てます。

# defaults:
ision=0
vison=0

while getopts "iv" option; do
    case "$option" in
        i)
            echo "interactive mode set"
            ision=1 ;;
        v)
            echo "verbose mode"
            vison=1 ;;
        *)
            exit 1 ;;
    esac
done
shift $(( OPTIND - 1 ))

(( vison )) && echo 'This is a verbose message'

if (( ision )); then
   # interactive code
fi

整数であれば、計算がisionはるかに簡単になります。その後、上記のようにその値をテストvisonできます。(( vison ))

また、無効なコマンドオプション文字列が表示されますgetopts。私が知っている限り、両方のオプションにパラメータはありません。つまり、文字列にコロンがあってはいけません。オプションが引数を取る場合は、次のようにコロンを続けてくださいv:

breakコマンドラインを解析するときにこれを行わないでください。解析が停止します。代わりに、フラグを設定して必要な他のタスクを実行し、ループが続行されるようにします。私はあなたがおそらく次のいずれかであるCについての知識を持っていると仮定します。する必要はステートメントから出てきbreakます。ここは違います。caseswitch

デバッグサポートを除いて、コマンドラインを解析するときに出力を生成しないでください。多くのユーティリティには、互いを取り消すフラグがあります。たとえば、-v冗長モードの場合、-q「静かな」モードで、コード出力が「冗長モードに入った後」「静かなモードに入る」というのはノイズだけです。

しかし、同様のことを行うには(相互排他的なオプションの処理)、次のようにします。

case "$option" in
    q)
        quiet=1
        verbose=0 ;;
    v)
        verbose=1
        quiet=0   ;;

    # etc.

ユーザーが使用する場合、-qv最初quietは1に設定され、次にverbose0に設定され、次に値が反転されます。この場合、コマンドラインを手動で設定したのか、スクリプトを呼び出して設定したのかわからないため、エラーは報告されません。

exit 1不明なコマンドラインオプションが与えられたときに実行されるステートメントを挿入しました。これはユーザーが間違いを犯したという意味であり、その時点からコマンドラインの内容を盲目的に信頼することは危険である可能性があるため、おそらく良いことです。

shift(解決されたオプションの削除)は上記のようにする必要があります。 Shift キーを押すと、$OPTIND - 2引数リストから多くの項目が削除されます。

また、読みやすくするためにインデントを改善し、デバッグとメンテナンスも簡単にしました。


スクリプトの残りの部分は詳細には見られませんでしたが、引用されていない変数拡張がたくさん見つかりました。指定されたファイル名にスペース(または他のスペース文字)が含まれていると問題が発生する可能性があるため、これを行わないでください。

特に$@ループなどで使用される場合は、引用符が必要です。これにより、コマンドライン引数がスペース(より正確には内容$IFS)で区切られるのを防ぎ、名前にグロービングパターン文字が含まれている場合に誤ってファイル名のグロビングを防ぐことができます。

かなり多くのcontinue理論もあります。 IMHOこれらのコードはコードフローに従うのが難しいため、削除する必要があります(特にコードが正しくインデントされていない場合)。それ自体には問題はありませんが、コードがさまざまな条件を適切に処理することで削除できます。少なくとも1つのケースでは、ステートメントのecho直後にステートメントがありますcontinue。これは文が実行されないことを意味しますecho

    continue
    echo "cant remove safe_rm_restore"

答え2

いくつかの短縮比較を使用できます。これは、Cおよび他の多くの言語の?:表記と同様の方法でリストされているif/then/elseステートメントです。 trueの場合、&&を使用して比較を実行し、ブロックを実行し、||を使用してブロックを実行できます。 false の場合、ブロックを実行します。

$ vison=true 
$ [[ "$vison" == "true" ]] && vison=false || vison=true
$ echo $vison
false
$ [[ "$vison" == "true" ]] && vison=false || vison=true
$ echo $vison
true

詳細なログ記録を確認するために同じことを行うこともできます。

[[ "$vison" == "true" ]] && echo "this is shown only in verbose mode"

答え3

シェルには、ブール値を簡単に表現できるようにする命令falseと命令があります。true詳細情報を表示するための一般的なアプローチは、ログレベルを使用することです。ここで、各発生は-vログレベルを増減します。-q

interactive=false
log_level=1

log() {
  local level="$1"
  if [ "$level" -ge "$log_level" ]; then
    shift
    local IFS=" "
    printf '%s\n' "$*"
  fi
}


while getopts iqv option; do
    case $option in
        i)
            log 2 "interactive mode set"
            interactive=true;;
        v)
            log 2 "increasing log level"
            log_level=$((log_level + 1));;
        q)
            log 2 "decreasing log level"
            log_level=$((log_level - 1));;
        *)
            exit 1 ;;
    esac
done
shift "$((OPTIND - 1))"

log 2 'This is a verbose message'
log 3 'This is a debug message'

if "$interactive"; then
   # interactive code
fi

# or:

ask() { # args: var default question
  if "$interactive"; then
    printf %s "$3"
    IFS= read -r "$1"
  else
    eval "$1=\$2"
  fi
}

yesno() { # args: default question
  local answer="$1"
  ask answer "$1" "$2"
  case $answer in
    ([yY][eE][sS] | y | Y) return 0;;
    ([nN][oO] | n | N) return 1;;
    (*) case $1 in
          ([yY][eE][sS] | y | Y) return 0;;
          ([nN][oO] | n | N) return 1;;
          (*) log >&2 -1 "Wrong default value $default"; exit 1;;
        esac;;
  esac
}

if yesno no "Are you OK with that (yes/[no])? "; then
   log 1 OK do it
   ...
fi

上記のコード(テストされていない)はDebianポリシーに準拠しているため、POSIXまたはPOSIX(そうでない場合はPOSIX)shで構成されているかどうかに関係なくDebianで動作します。dashlkshbashlocal

関連情報