Bashスクリプトで「テスト$ 2&&」とはどういう意味ですか?

Bashスクリプトで「テスト$ 2&&」とはどういう意味ですか?

次のコードを含む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 anythingelsetrueを返します(ただし、test -t一部のシェルではstdoutが端末であることを確認するためにチェックされます))。

しかし、作者は変数の周りの引用符(実際にはすべての変数)を忘れていました。これが意味するのは、$2分割+グローブ演算子によって異なります。したがって、$2文字$IFS(デフォルトではスペース、タブ、改行)またはグローバル文字(*、、、?)が含まれていると[...]正しく機能しません。

空の場合$2(たとえば、2つ未満の引数が渡された場合、または2番目の引数が空の場合)の代わりに、test $2になります。引数をまったく受け取りません(空またはそうでない場合)。testtest ''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成功した場合にのみ実行されます。この場合の違いは、コマンドの全リストの終了状態が、この場合に&&実行された最後のコマンドの終了状態になることです。失敗するコードはcmd1trueを返しませんが(ここでは問題は発生しませんがset -e)、この場合実行されない場合は0(成功)にifなります。cmd2cmd2

そのため、次cmd1のように使用されます。状況(失敗とみなされない場合質問)、通常これを使用するのが最善です。if特にスクリプトの終了状態を定義するので、スクリプトが最後に実行する操作である場合はさらにそうです。また、コードがより明確になります。

このcmd1 && cmd2形式は、次のように一般的に使用されます。状況彼らは自分で以下が好きです:

if cmd1 && cmd2; then...
while cmd1 && cmd2; do...

これは、これら2つのコマンドの終了ステータスに興味がある場合です。

答え2

test $2 && some_commandこれは2つのコマンドで構成されています。

  • test $2$22番目の引数()の拡張文字列の長さがゼロでないことを確認してください。つまり、test -n $2[ -n $2 ])を確認する必要があります。スペースのある値は、周囲に引用符を使用しないためブロックされます$2。これをtest使用する必要がありますtest "$2"

  • &&段落評価演算子です。つまり、&&前のコマンドが成功した場合にのみ、次のコマンドが実行されます(つまり、終了コードは0です)。したがって、上記の例では、成功したsome_command場合にのみ実行されます(つまり、文字列が長さではtest $2ない場合)。その後some_command実行されます。

関連情報