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
ます。ここは違います。case
switch
デバッグサポートを除いて、コマンドラインを解析するときに出力を生成しないでください。多くのユーティリティには、互いを取り消すフラグがあります。たとえば、-v
冗長モードの場合、-q
「静かな」モードで、コード出力が「冗長モードに入った後」「静かなモードに入る」というのはノイズだけです。
しかし、同様のことを行うには(相互排他的なオプションの処理)、次のようにします。
case "$option" in
q)
quiet=1
verbose=0 ;;
v)
verbose=1
quiet=0 ;;
# etc.
ユーザーが使用する場合、-qv
最初quiet
は1に設定され、次にverbose
0に設定され、次に値が反転されます。この場合、コマンドラインを手動で設定したのか、スクリプトを呼び出して設定したのかわからないため、エラーは報告されません。
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で動作します。dash
lksh
bash
local