以下のように "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" を渡さないため混乱します。
どうなりますか?
答え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
答え2
[
最初に明確なのはtest
、または引数の間にスペースを提供する必要があることです[[
。
if [ "$1" = 1 ];
Bashでは、[[ ]]
トークン化、パス名拡張などの条件式に不要な操作を実行しないため、usingを使用することをお勧めします。二重引用符で囲む必要もありません。==
より読みやすい演算子を使用することもできます。
if [[ $1 == 1 ]];
*
追加された説明:2番目のオペランドにも変数が含まれている場合は、引用符で囲む必要があります。これは、認識された文字(など)が含まれていると?
パターンマッチングの影響を受ける可能性があるためです。使用されている場合、他の形式(など)を使用する[]
と、拡張されたワイルドカードまたはパターンマッチングが可能になります。パターンとしても認識されます。バラよりshopt -s extglob
@()
!()
パターンマッチング。
<
同じ演算子の場合、>
2番目の引数を引用しないと、他の結果が出るバグが発生したため、まだ必要になることがあります。
最初のオペランドは何も適用されません。
また、次の簡単なバリエーションを検討してください。
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
-
答え3
答え4
一つだけおすすめしたい持ち運べるしかし、それはよりクリーンなオプションでもあります。すごいいいえUniversal(ユニバーサルは必要ありませんが、なぜシェルスクリプトを書くのですか?)
#! /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
知っていますが、将来の読者がこれを覚える必要がないように引用文をそこに置く方が良いと思います。)