次のコードを含むbashスクリプトを見ています。
#!/bin/sh
set -e # Exit if any command fails
# If multiple args given run this script once for each arg
test $2 && {
for arg in $@
do $0 $arg
done
exit
}
.
.
.
コメントで述べたように、目的は「複数の引数がある場合は各引数に対してスクリプトを実行する」ことです。これをテストするためのランチャーコードがあります。
# install-unit
# If multiple args given run this script once for each arg
test $2 && {
echo "\$0: $0"
echo "\$1: $1"
echo "\$2: $2"
echo "test \$2 && is true"
}
test $2 && {
# note this is just a regular bash for loop
# http://goo.gl/ZHpBvT
for arg in $@
do $0 $arg
done
exit
}
echo "running: $1"
次の結果を提供します。
sh ❯ ./multiple-run.sh cats and dogs and stuff
$0: ./multiple-run.sh
$1: cats
$2: and
test $2 && is true
running: cats
running: and
running: dogs
running: and
running: stuff
sh ❯ ./multiple-run.sh cats
running: cats
test $2 && {}
誰かがその部分と組み込みexit
シェルを解放できることを願っています。最初はtest $2
引数がもっとあるかどうかを確認すると思いましたが、そうかもしれませんね。ところで、「and」で区切られた式が2つあるようで、奇妙に見え、組み込み関数が正確に何をするのか混乱します&&
。exit
。
例とドキュメント参照を含む簡単な英語の説明をお願いします:)
ありがとうございます!
編集者:Stéphane Chazelasに感謝します。 forループ構文の変更により混乱している人は、この記事の3番目の項目を確認してください。オタク物記事。結論として:
echo "positional parameters"
for arg do
echo "$arg"
done
echo "\nin keyword"
for arg in "$@"
do echo "$arg"
done
私たちに与える:
❯ ./for-loop-positional.sh cats and dogs
positional parameters
cats
and
dogs
in keyword
cats
and
dogs
答え1
これは間違った書き方です。
#!/bin/sh -
set -e # Exit if any command fails
# If multiple args given run this script once for each arg
if [ "$#" -gt 1 ]; then
for arg do
"$0" "$arg"
done
exit
fi
作成者が望むのは、2番目のパラメータが空でない文字列であることを確認することだと思います。これは、2番目のパラメータを渡すことができますが、空の文字列であるため、パラメータが少なくとも2つあることを確認するのとは異なります。
test somestring
短い形式
test -n somestring
somestring
空の文字列でない場合は true を返します。 (test ''
falseを返し、test anythingelse
trueを返します(ただし、test -t
一部のシェルではstdoutが端末であることを確認するためにチェックされます))。
しかし、作者は変数の周りの引用符(実際にはすべての変数)を忘れていました。これが意味するのは、$2
分割+グローブ演算子によって異なります。したがって、$2
文字$IFS
(デフォルトではスペース、タブ、改行)またはグローバル文字(*
、、、?
)が含まれていると[...]
正しく機能しません。
空の場合$2
(たとえば、2つ未満の引数が渡された場合、または2番目の引数が空の場合)の代わりに、test $2
になります。引数をまったく受け取りません(空またはそうでない場合)。test
test ''
test
幸いtest
、この場合、パラメータはfalseを返しません。 trueを返すよりも少し優れているtest -n $2
ため(これtest -n
はと同じになるためtest -n -n
)、場合によってはこのコードが機能するようです。
要約する:
2つ以上のパラメータが渡されるかどうかをテストします。
[ "$#" -gt 1 ]
または
[ "$#" -ge 2 ]
変数が空でないことをテストします。
[ -n "$var" ] [ "$var" != '' ] [ "$var" ]
これらはすべてPOSIX実装で信頼できますが、
[
非常に古いシステムを処理する必要がある場合は、次のものを使用する必要があります。[ '' != "$var" ]
一方、、、...など
[
の値を実装する場合は$var
=
-t
(
変数が定義されているかどうかをテストします(スクリプトに2番目の引数が渡されたかどうかをテストするために使用できますが、
$#
読みやすく、使いやすくなります)。[ "${var+defined}" = defined ]
(またはそれに対応する.コマンドにエイリアスを使用する方がtest
一般的です。)[
test
cmd1 && cmd2
それでは、との違いについて話してくださいif cmd1; then cmd2; fi
。
cmd2
どちらもcmd1
成功した場合にのみ実行されます。この場合の違いは、コマンドの全リストの終了状態が、この場合に&&
実行された最後のコマンドの終了状態になることです。失敗するコードはcmd1
trueを返しませんが(ここでは問題は発生しませんがset -e
)、この場合実行されない場合は0(成功)にif
なります。cmd2
cmd2
そのため、次cmd1
のように使用されます。状況(失敗とみなされない場合質問)、通常これを使用するのが最善です。if
特にスクリプトの終了状態を定義するので、スクリプトが最後に実行する操作である場合はさらにそうです。また、コードがより明確になります。
このcmd1 && cmd2
形式は、次のように一般的に使用されます。状況彼らは自分で以下が好きです:
if cmd1 && cmd2; then...
while cmd1 && cmd2; do...
これは、これら2つのコマンドの終了ステータスに興味がある場合です。
答え2
test $2 && some_command
これは2つのコマンドで構成されています。
test $2
$2
2番目の引数()の拡張文字列の長さがゼロでないことを確認してください。つまり、test -n $2
([ -n $2 ]
)を確認する必要があります。スペースのある値は、周囲に引用符を使用しないためブロックされます$2
。これをtest
使用する必要がありますtest "$2"
。&&
段落評価演算子です。つまり、&&
前のコマンドが成功した場合にのみ、次のコマンドが実行されます(つまり、終了コードは0です)。したがって、上記の例では、成功したsome_command
場合にのみ実行されます(つまり、文字列が長さではtest $2
ない場合)。その後some_command
実行されます。