同僚は最近コードレビューで[[ ]]
構文が次のような構文で[ ]
より優先されるべきであると主張しました
if [ "`id -nu`" = "$someuser" ] ; then
echo "I love you madly, $someuser"
fi
彼は理論的根拠を提供できなかった。ありますか?
[[
は驚きが少なく、一般的に安全です。しかし、移植性はありません - POSIXはそれが何をするのかを明記せず、いくつかのシェルだけがそれをサポートします(bashの他に、kshもそれをサポートすると聞きました)。たとえば、
[[ -e $b ]]
ファイルが存在するかどうかをテストします。しかし[
では、引数を分割して$b
のように展開するので("a*"
は文字通り)、[[
を引用符で囲む必要があります。これは[
が外部プログラムになり、他のすべてのプログラムと同じようにその引数を受け取る方法とも関係しています(ただし組み込みプログラムになることもできますが、それでもこの特別な処理は行われません)。
[[
には、=~
との正規表現マッチングや、Cのような言語で知られている演算子など、他にもいくつかのNice機能があります。これが良いページです: test、[
と[[
の違いは何ですか? and Bash Tests
行動の違い
Bash 4.3.11のいくつかの違い:
POSIX対Bash拡張機能:
通常コマンドvsマジック
[
は、奇妙な名前の通常のコマンドです。
]
は[
の単なる引数であり、これ以上の引数が使用されないようにします。
Ubuntu 16.04には、coreutilsが提供する/usr/bin/[
に実際に実行可能ファイルがありますが、bashの組み込みバージョンが優先されます。
Bashがコマンドを解析する方法に変更はありません。
特に、<
はリダイレクト、&&
および||
は複数のコマンドを連結し、( )
は\
でエスケープされない限りサブシェルを生成し、Wordの展開は通常どおり行われます。
[[ X ]]
は、X
を魔法のように解析する単一の構成体です。 <
、&&
、||
、および()
は特別に扱われ、Wordの分割ルールは異なります。
=
や=~
などの違いもあります。
Basheseの場合:[
は組み込みコマンドであり、[[
はキーワードです。 https://askubuntu.com/questions/445749/whats-the-difference-between-Shell -builtin-and-Shell-keyword
<
[[ a < b ]]
:辞書編集の比較[ a \< b ]
:上記と同じ。 \
が必要です。または、他のコマンドと同様にリダイレクトを行います。バッシュ拡張。expr a \< b > /dev/null
:POSIX同等²、参照: Bashで辞書式の以下の文字列をテストする方法?&&
および||
[[ a = a && b = b ]]
:true、論理and[ a = a && b = b ]
:構文エラー、&&
ANDコマンド区切り文字として解析cmd1 && cmd2
[ a = a -a b = b ]
:同等ですが、POSIX³で非推奨[ a = a ] && [ b = b ]
:POSIXおよび同等の信頼できる(
[[ (a = a || a = b) && a = b ]]
:false[ ( a = a ) ]
:構文エラー、()
はサブシェルとして解釈されます[ \( a = a -o a = b \) -a a = b ]
:同等ですが、()
はPOSIXで非推奨になりました{ [ a = a ] || [ a = b ]; } && [ a = b ]
POSIX相当⁵展開時の単語分割とファイル名生成(split + glob)
x='a b'; [[ $x = 'a b' ]]
:true、引用符は不要x='a b'; [ $x = 'a b' ]
:構文エラー、[ a b = 'a b' ]
に展開x='*'; [ $x = 'a b' ]
:現在のディレクトリに複数のファイルがある場合の構文エラー。x='a b'; [ "$x" = 'a b' ]
:POSIXと同等=
[[ ab = a? ]]
:true パターンマッチング (* ? [
は魔法)を行うため。現在のディレクトリ内のファイルに展開しません。[ ab = a? ]
:a?
globが展開されます。したがって、現在のディレクトリ内のファイルに応じて、trueまたはfalseになる場合があります。[ ab = a\? ]
:glob展開ではなくfalse=
と==
は[
と[[
の両方で同じですが、==
はBash拡張機能です。case ab in (a?) echo match; esac
:POSIXと同等[[ ab =~ 'ab?' ]]
:false⁴、''
で魔法を失います[[ ab? =~ 'ab?' ]]
:true=~
[[ ab =~ ab? ]]
:true、POSIX 拡張正規表現 一致、?
は展開されません[ a =~ a ]
:構文エラー。同等のbashはありません。printf 'ab\n' | grep -Eq 'ab?'
:POSIX同等(単一行データのみ)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
:POSIXと同等。推奨事項:常に[]
を使用します。
私が見たすべての[[ ]]
コンストラクトに対応するPOSIXがあります。
[[ ]]
を使用する場合:
[
は、奇妙な名前を持つ通常のコマンドであり、特別なセマンティクスは含まれていません。¹Kornシェルの同等の[[...]]
コンストラクトに触発された
²しかし、a
またはb
(+
またはindex
など)の一部の値で失敗し、a
とb
が似ている場合は数値比較を行います。 10進整数。 expr "x$a" '<' "x$b"
は両方を回避します。
³また、!
や(
のようなa
またはb
の一部の値でも失敗します。
bash 3.2以降で提供され、bash 3.1との互換性が提供されていない(BASH_COMPAT=3.1
など)
⁵ただし、グループ化(ここでは、不要なサブシェルを実行する{...;}
の代わりに(...)
コマンドグループ)は、||
および&&
シェル演算子としては必要ありません(反対に) ||
演算子と&&
[[...]]
演算子、または-o
/-a
[
演算子)の優先順位は同じです。したがって、[ a = a ] || [ a = b ] && [ a = b ]
は同等です。
[[ ]]
にはもっと多くの機能があります - 詳細については Advanced Bash Scripting Guide をご覧ください。特に拡張テストコマンド第7章テスト のセクション。
ちなみに、ガイドノートとして、[[ ]]
がksh88(1988年版のKornシェル)で導入されました。
から どのコンパレータ、テスト、かっこ、または二重かっこ、最速? ( http://bashcurescancer.com )
二重括弧はテストとしての単一括弧がシェル組み込みコマンドである(そして実際には同じコマンドである)「複合コマンド」です。したがって、シングルブラケットとダブルブラケットは異なるコードを実行します。
Testとシングルブラケットは、別々の外部コマンドとして存在するため、最も移植性があります。ただし、リモートの最新バージョンのBASHを使用している場合は、二重括弧がサポートされています。
[[を使えない典型的な状況はautotoolsのconfigure.acスクリプトにあります。大括弧には特別な意味があります。したがって、[または[[の代わりにtest
を使用する必要があります。testと[は同じです。プログラム。
次のことに興味がある場合 Googleのスタイルガイド :
Test、[および[[
[[...]]は、[[and]]と[[...]]の間でパス名の展開やワード分割が行われないため、エラーを削減します。
# This ensures the string on the left is made up of characters in the
# alnum character class followed by the string name.
# Note that the RHS should not be quoted here.
# For the gory details, see
# E14 at https://tiswww.case.edu/php/chet/bash/FAQ
if [[ "filename" =~ ^[[:alnum:]]+name ]]; then
echo "Match"
fi
# This matches the exact pattern "f*" (Does not match in this case)
if [[ "filename" == "f*" ]]; then
echo "Match"
fi
# This gives a "too many arguments" error as f* is expanded to the
# contents of the current directory
if [ "filename" == f* ]; then
echo "Match"
fi