次のような「teleport.sh」という名前のシェルスクリプトがあります。
if [ $1="1" ];
then
shift
mv "$@" ~/lab/Sun
Elif [ $1="2" ];
then
shift
mv "$@" ~/lab/Moon
Elif [ $1="3" ];
then
shift
mv "$@" ~/lab/Earth
fi
私が実行すると:
sh teleport.sh 2 testfile
このtestfile
は~/lab/Sun
ディレクトリに移動されますが、そのスクリプトに1または '1'を渡さなかったため、非常に混乱しています。
ここで何が問題になっていますか?
スペースを使用すると問題が解決します。
if [ "$1" = 1 ];
then
shift
mv "$@" ~/lab/Sun
Elif [ "$1" = 2 ];
then
shift
mv "$@" ~/lab/Moon
Elif [ "$1" = 3 ];
then
shift
mv "$@" ~/lab/Earth
fi
これはきれいですが:
#!/bin/bash
action=$1
shift
files=("$@")
case $action in
1) mv -- "${files[@]}" ~/lab/Sun ;;
2) mv -- "${files[@]}" ~/lab/Moon ;;
3) mv -- "${files[@]}" ~/lab/Earth ;;
esac
最初の明らかなことは、_[
_、test
または_[[
_の引数の間にスペースを入れる必要があることです。
_if [ "$1" = 1 ];
_
Bashでは、_[[ ]]
_を使用することをお勧めします。Wordの分割やパス名の展開などの条件式には不要なことをしないためです。二重引用符を囲む引用符も必要ありません。より読みやすい演算子_==
_も使用できます。
_if [[ $1 == 1 ]];
_
追加の注記:2番目のオペランドにも変数が含まれる場合、_*
_、_?
_、_[]
_などの認識可能な文字が含まれているとパターンマッチングの対象となる可能性があるため、引用符が必要です。拡張されている場合_shopt -s extglob
_を使用すると、グロビングまたはパターンマッチングが有効になります。@()
、!()
などの他の形式もパターンとして認識されます。 パターンマッチング を参照してください。
_<
_や_>
_などの演算子を使用すると、2番目の引数を引用符で囲まないと異なる結果が発生するというバグにかつて遭遇したことがあるので、まだ必要な場合があります。
第1オペランドについては、何も適用されません。
この単純なバリエーションも検討してください。
_case "$1" in
1)
mv -- "${@:2}" ~/lab/Sun
;;
2)
mv -- "${@:2}" ~/lab/Moon
;;
3)
mv -- "${@:2}" ~/lab/Earth
;;
esac
_
または凝縮:
_case "$1" in
1) mv -- "${@:2}" ~/lab/Sun ;;
2) mv -- "${@:2}" ~/lab/Moon ;;
3) mv -- "${@:2}" ~/lab/Earth ;;
esac
_
_"${@:2}"
_は、部分文字列展開または配列メンバー展開の形式で、_2
_はオフセットです。これにより、2番目の値から拡張が開始されます。これにより、shift
を使用する必要がない場合があります。
追加された_--
_は、mv
がダッシュ(_-
_)で始まるファイル名を無効なオプションとして認識しないようにします。
なぜこれが起こっているのかという質問に答えるために、[
aka test
のこの動作は POSIXに文書化されています :
次のリストで、$ 1、$ 2、$ 3、および$ 4は、テストのために提示された引数を表します。
[...]
1つの引数:
$ 1がnullでない場合はtrue(0)を終了します。それ以外の場合は、falseを終了します。
Nullでない1つの引数2=1
を渡しているため、test
は正常に終了します。
他の投稿(および shellcheck )が指摘しているように、同等性を比較する場合は、代わりに3つの引数2
、=
、および1
を渡す必要があります。
私はportableをお勧めしたいのですが、もっとすてきな代替手段もあります。 Bashはnotユニバーサルです(そして、ユニバーサルが必要ない場合は、なぜシェルスクリプトを作成しているのですか?)
#! /bin/sh
action="$1"
shift
case "$action" in
1) dest=Sun ;;
2) dest=Moon ;;
3) dest=Earth ;;
*) echo "Unrecognized action code '$action' (must be 1, 2, or 3)" >&2; exit 1 ;;
esac
mv -- "$@" ~/lab/"$dest"
(注意事項:はい、私は$action
のcase "$action" in
行は不要ですが、とにかくそこに置くのがベストだと思います。将来の読者が覚えておく必要がないようにするためです。)