web-dev-qa-db-ja.com

testまたは[または[[は、bashシェル間と他のシェルの間の両方に移植性がありますか?

できると思います

$ [ -w /home/durrantm ] && echo "writable"
writable

または

$ test -w /home/durrantm && echo "writable"
writable

または

$ [[ -w /home/durrantm ]] && echo "writable"
writable

3番目の構文を使用するのが好きです。それらはすべての点で同等であり、すべてのネガティブおよびエッジケースと同等ですか?移植性に違いはありますか? UbuntuのbashとOS Xまたはそれより古い/新しいbashバージョンの間。 4.0の前/後、両方とも同じように式を展開しますか?

44
Michael Durrant

[testコマンドの同義語であり、同時にbashビルトインおよび個別のコマンドです。ただし、[[bashキーワードであり、一部のバージョンでのみ機能します。したがって、移植性の理由から、単一の[]またはtestを使用するほうがよいでしょう。

[ -w "/home/durrantm" ] && echo "writable"
31
Costas

はい、違いがあります。最も移植性が高いのはtestまたは[ ]です。これらは両方とも POSIX test仕様 の一部です。

if ... fi構成要素も POSIX によって定義されており、完全に移植可能である必要があります。

[[ ]]ksh機能であり、bashの一部のバージョンにも存在します( すべての最新バージョン )、zshおよびおそらく他の場所にありますが、shまたはdashまたはその他のさまざまな単純なシェルにはありません。

したがって、スクリプトを移植可能にするには、[ ]testまたはif ... fiを使用します。

35
terdon

[] && cmdif .. fi構成と同じではないことに注意してください。

時々その動作はかなり似ており、[] && cmdの代わりにif .. fiを使用できます。しかし、ときどき。 if条件またはif .. else .. fiが必要な場合に実行するコマンドが複数ある場合は、ロジックに注意してください。

いくつかの例:

[ -z "$VAR" ] && ls file || echo wiiii

と同じではありません

if [ -z $VAR ] ; then
  ls file
else
  echo wiii
fi

lsが失敗した場合、echoは実行されますが、ifでは発生しません。

もう一つの例:

[ -z "$VAR" ] && ls file && echo wiii

と同じではありません

if [ -z "$VAR" ] ; then
   ls file
   echo $wiii
fi

この構造は同じように動作しますが

[ -z "$VAR" ] && { ls file ; echo wiii ; }

エコー後の;は重要であり、そこにある必要があることに注意してください。

上記のステートメントを再開すると、

[] && cmd ==最初のコマンドが成功した場合、次のコマンドを実行します

if .. fi ==条件(テストコマンドの場合もあります)の場合、コマンドを実行します

そのため、[[[の間の移植性のために、[のみを使用してください。

ifはPOSIX互換です。したがって、[ifのどちらかを選択する必要がある場合は、タスクと期待される動作を確認することを選択してください。

20
rush

実際にはifではなくtestを置き換えるのは&&です。シェルスクリプトのifステートメントは、コマンドが「成功」(ゼロ)を返したかどうかをテストします)終了ステータス。あなたの例では、コマンドは[です。

したがって、実際にはここで2つの点が異なります。テストを実行するために使用するコマンドと、そのテストの結果に基づいてコードを実行するために使用する構文です。

テストコマンド:

  • test is 標準化されたコマンド 文字列とファイルのプロパティを評価します。あなたの例では、コマンドtest -w /home/durrantmを実行しています
  • [は、同等に標準化されたそのコマンドのエイリアスであり、括弧で囲まれた式のように見えるように、]の必須の最後の引数があります。だまされてはいけません、それはまだ単なるコマンドです(あなたのシステムには/bin/[というファイルがあるかもしれません)
  • [[は、一部のシェルに組み込まれたtestコマンドの拡張バージョンですが、同じPOSIX標準の一部ではありません。ここには使用していない追加オプションが含まれています

条件式:

  • &&演算子( ここでは標準化 )は、2つのコマンドを評価し、両方が0を返す場合は0(trueを表す)を返すことにより、論理AND演算を実行します。最初のコマンドがゼロを返した場合にのみ2番目のコマンドを評価するため、単純な条件式として使用できます
  • if ... then ... fi構文( ここでは標準化 )は、「真理」を判断する同じ方法を使用しますが、then句内のステートメントの複合リストではなく、 &&ショートサーキットによって提供されるコマンド、およびElif句とelse句を提供します。これらの句は、&&||だけを使用して書き込むのは困難です。 ifステートメントでは、条件の前後に角括弧がないことに注意してください。

したがって、次の例はすべて移植可能であり、完全に同等であり、例のレンダリングになります。

  • test -w /home/durrantm && echo "writable"
  • [ -w /home/durrantm ] && echo "writable"
  • if test -w /home/durrantm; then echo "writable"; fi
  • if [ -w /home/durrantm ]; then echo "writable"; fi

次のものも同等ですが、[[の非標準的な性質のため、移植性は低くなります。

  • [[ -w /home/durrantm ]] && echo "writable"
  • if [[ -w /home/durrantm ]]; then echo "writable"; fi
9
IMSoP

移植性を確保するには、test/[を使用します。ただし、移植性が必要ない場合は、自分自身およびスクリプトを読む他の人の健全性のために、[[を使用します。 :)

BashFAQWhat is the difference between test, [ and [[ ?も参照してください。

7
PM 2Ring

ボーンのような世界の外での移植性が必要な場合は、次のようにします。

test -w /home/durrantm && echo writable

最もポータブルです。 Bourne、cshおよびrcファミリーのシェルで動作します。

test -w /home/durrantm && echo "writable"

writableファミリのシェルでrcではなく"writable"を出力します(rcesakanga"は特別ではありません)。

[ -w /home/durrantm ] && echo writable

[$PATHコマンドがないシステムのcshまたはrcファミリーのシェルでは機能しません(testですが、その[エイリアスは除きます)。

if [ -w /home/durrantm ]; then echo writabe; fi

bourneファミリのシェルでのみ機能します。

[[ -w /home/durrantm ]] && echo writable

ksh(元の場所)、zshbash(Bourneファミリの3つすべて)でのみ機能します。

必要なfishシェルでは機能しません。

[ -w /home/durrantm ]; and echo writable

または:

if [ -w /home/durrantm ]; echo writable; end
7

どちらかを選択する最も重要な理由if foo; then bar; fiまたはfoo && barは、コマンド全体の終了ステータスが重要かどうかです。

比較:

#!/bin/sh
set -e
foo && bar
do_baz

と:

#!/bin/sh
set -e
if foo; then bar; fi
do_baz

彼らは同じことをしていると思うかもしれません。ただし、fooが失敗した場合(または、視点に応じてfalseの場合)、最初の例では、スクリプトが終了しているため、do_bazは実行されません... set -eは、コマンドがfalseステータスを返した場合にシェルをすぐに終了するように指示します。次のような場合に非常に役立ちます。

cd /some/directory
rm -rf *

何らかの理由でcdが失敗した場合にスクリプトの実行を継続する必要はありません。

0
wurtel