同僚は最近、コードレビューで、次のような[[ ]]
構文でこの構文が優先されると主張しました。[ ]
if [ "`id -nu`" = "$someuser" ] ; then
echo "I love you madly, $someuser"
fi
彼は理論的根拠を提供できなかった。ありますか?
同僚は最近、コードレビューで、次のような[[ ]]
構文でこの構文が優先されると主張しました。[ ]
if [ "`id -nu`" = "$someuser" ] ; then
echo "I love you madly, $someuser"
fi
彼は理論的根拠を提供できなかった。ありますか?
回答:
[[
驚きが少なく、一般的に安全に使用できます。ただし、移植性はありません。POSIXは何をするかを指定せず、一部のシェルのみがサポートします(bashのほかに、kshもサポートしていると聞きました)。たとえば、次のことができます
[[ -e $b ]]
ファイルが存在するかどうかをテストします。しかし[
、を使用$b
すると、引数を分割して"a*"
([[
文字列で文字列を受け取る)のように展開するため、を引用する必要があります。これは[
、外部プログラムになり、他のすべてのプログラムと同じように通常どおり引数を受け取ることにも関係します(組み込みにすることもできますが、この特別な処理はまだありません)。
[[
=~
には、Cライクな言語で知られているような演算子とともに正規表現のマッチングを行うなど、他にも優れた機能があります。:ここでは良いページはそれについてですテストの違いは何ですか、[
と[[
?およびBashテスト
[[ ]]
れ[ ]
ますが、と同じ意味で解釈されます。
#!/bin/sh
が、#!/bin/bash
BASH固有の機能に依存したらすぐに使用に切り替え、Bourneシェルポータブルではなくなったことを示します。
行動の違い
Bash 4.3.11のいくつかの違い:
POSIX対Bash拡張:
[
POSIX[[
Bashの拡張機能です ¹通常のコマンド対魔法
[
奇妙な名前の通常のコマンドです。
]
[
それ以上の引数が使用されないようにするための単なる引数です。
Ubuntu 16.04には、実際にはcoreutils/usr/bin/[
によって提供される実行可能ファイルがありますが、bash組み込みバージョンが優先されます。
Bashがコマンドを解析する方法に変更はありません。
特に、<
はリダイレクトされ、複数のコマンド&&
を||
連結し、( )
によってエスケープされない限りサブシェルを生成し\
、単語の展開は通常どおり行われます。
[[ X ]]
X
魔法のように解析される単一の構造です。<
、&&
、||
および()
特別に処理し、単語分割ルールは異なるされています。
とのような違いも=
あり=~
ます。
バシェス語で[
は:は組み込みコマンドであり[[
、キーワードです: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、論理的および[ 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?
グロブが拡張されます。したがって、現在のディレクトリ内のファイルに応じて、trueまたはfalseになります。[ ab = a\? ]
:false、グロブ拡張ではない=
そして==
、両方で同じである[
と[[
、しかし==
バッシュの拡張機能です。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があります。
あなたがあなたを使う[[ ]]
なら:
[
奇妙な名前の通常のコマンドであり、特別なセマンティクスは含まれていません。Ko [[...]]
Kornシェルの同等の構成に触発
²しかし、いくつかの値のために失敗したa
かb
(よう+
やindex
)と数値の比較であれば行いa
やb
小数、整数のような表情を。expr "x$a" '<' "x$b"
両方を回避します。
³ものいくつかの値のために失敗したa
かb
のような!
、または(
。
b bash 3.2以降で提供され、bash 3.1との互換性が有効になっていません(などBASH_COMPAT=3.1
)。
⁵(および演算子または/ 演算子とは対照的に)およびシェル演算子の優先順位が等しいため、グループ化(ここでは不要なサブシェルを実行する{...;}
代わりにコマンドグループを使用(...)
)は必要ありません。したがって同等です。||
&&
||
&&
[[...]]
-o
-a
[
[ a = a ] || [ a = b ] && [ a = b ]
[
同じ理由で使用しています。
[[ ]]
より多くの機能があります。詳細については、「高度なBashスクリプトガイド」を参照してください。具体的には、第7章の「テストコマンドの拡張」セクションをご覧ください。
ちなみに、ガイドノートとして、[[ ]]
ksh88(1988年版Kornシェル)で導入されました。
どのコンパレータ、テスト、ブラケット、またはダブルブラケット、最速のでしょうか?(http://bashcurescancer.com)
二重ブラケットは「複合コマンド」であり、テストと単一ブラケットはシェル組み込みです(実際には同じコマンドです)。したがって、シングルブラケットとダブルブラケットは異なるコードを実行します。
テストと単一のブラケットは、独立した外部コマンドとして存在するため、最も移植性があります。ただし、リモートで最新バージョンのBASHを使用している場合は、二重ブラケットがサポートされます。
[[
がもたらすかもしれないことについてあまり気にすることができませんでした。しかし、その後、私は古い学校の古いおならです:-)
[
とtest
外部バージョンも存在していても。
PS1=...crazy stuff...
および/または$PROMPT_COMMAND
)。これらについては、スクリプトの実行に目に見えるほどの遅延を望まない。
apt-get update
前回の実行からX時間以上経過している場合は実行する必要があります。コードの制約のリストが長すぎて移植性がなくなると、非常に安心です。
あなたがGoogleのスタイルガイドに従うことに夢中なら:
テスト、[
および[[
[[ ... ]]
なしパス名展開としてエラーを低減または単語分割が間に起こる[[
と]]
し、[[ ... ]]
正規表現のマッチングを可能にし[ ... ]
ません。
# 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
[[ -d ~ ]]
trueを返します(これ~
はに展開されたことを意味します/home/user
)。グーグルはもっと正確に書いているはずだと思う。
[[]]二重括弧は特定のバージョンのSunOSではサポートされておらず、関数宣言内では完全にサポートされていません:GNU bash、バージョン2.02.0(1)-release(sparc-sun-solaris2.6)
簡単に言えば、[[は別のプロセスをフォークしないため、より優れています。ブラケットがないか単一のブラケットは、別のプロセスをフォークするため、二重ブラケットよりも低速です。
type [
してこれを確認してください。
[[
、とは異なり[
、bashコマンドラインインタープリターによって解釈される構文です。bashで入力してみてくださいtype [[
。unix4linuxは正解です。古典的なBourneシェル[
テストは新しいプロセスを分岐して真理値を決定しますが、[[
構文(bash、zshなどによってkshから借用)はそうではありません。
[
が、BashおよびDash(/bin/sh
Debian派生のすべてのLinuxディストリビューション)に組み込まれています。
[[
コードが良いと明確であることではなく、その日を覚えているときに、ポートよでないデフォルトのシェルを使用してシステム上のscriptworksbash
やksh
、など[
は醜くて扱いにくいですがAK-47
、どんな状況でも機能します。