シェル スクリプトでバッククォートの代わりに $() を使用する利点は何ですか?
質問
コマンドラインの出力をキャプチャするには 2 つの方法があります。 bash
:
レガシー Bourne シェルのバックティック
``
:var=`command`
$()
構文 (私の知る限り、これは Bash 固有であるか、少なくともオリジナルの Bourne のような非 POSIX の古いシェルではサポートされていません)var=$(command)
バッククォートと比較して、2 番目の構文を使用することに利点はありますか?それとも、この 2 つは完全に 100% 同等ですか?
解決
主要なものは、 nest を失うことなく、何らかの形のエスケープがバックトックに機能するかどうかを把握しようとすることなく、コマンド内のコマンドを維持することができます。
例はやや作りました:
.
deps=$(find /dir -name $(ls -1tr 201112[0-9][0-9]*.txt | tail -1l) -print)
2011年12月(a)。からの最古の日付のテキストファイルと同じ名前を持つ/dir
ディレクトリツリーのすべてのファイルのリストを表示します。
もう1つの例は、親ディレクトリの名前(フルパスではなく)を取得するようなものです。
.
pax> cd /home/pax/xyzzy/plugh
pax> parent=$(basename $(dirname $PWD))
pax> echo $parent
xyzzy
(a) specific コマンドが実際には機能しないかもしれません、私は機能をテストしていません。それで、あなたがそれのために私を投票したら、あなたはその意図を見失った:-)それはあなたがどのようにして巣箱のためのものとしてのイラストのようなものです。
他のヒント
gcc
がインストールされている場所に対応するlibディレクトリを見つけたいとします。あなたは選択肢があります:
libdir=$(dirname $(dirname $(which gcc)))/lib
libdir=`dirname \`dirname \\\`which gcc\\\`\``/lib
.
最初のものは2番目のものよりも簡単です。
バッククォート (`...`
) は、POSIX と互換性のない最も古い bourne-shell でのみ必要とされるレガシー構文です。 $(...)
POSIX は、いくつかの理由から POSIX の方が好まれます。
バックスラッシュ (
\
) バックティック内のバッククォートは、非自明な方法で処理されます。$ echo "`echo \\a`" "$(echo \\a)" a \a $ echo "`echo \\\\a`" "$(echo \\\\a)" \a \\a # Note that this is true for *single quotes* too! $ foo=`echo '\\'`; bar=$(echo '\\'); echo "foo is $foo, bar is $bar" foo is \, bar is \\
内部でネストされた引用符
$()
はるかに便利です:echo "x is $(sed ... <<<"$y")"
の代わりに:
echo "x is `sed ... <<<\"$y\"`"
または次のようなことを書きます:
IPs_inna_string=`awk "/\`cat /etc/myname\`/"'{print $1}' /etc/hosts`
なぜなら
$()
引用にまったく新しいコンテキストを使用しますBourne シェルと Korn シェルではバックスラッシュが必要ですが、Bash とダッシュではバックスラッシュが必要ないため、移植性はありません。
コマンド置換をネストする構文はより簡単です。
x=$(grep "$(dirname "$path")" file)
よりも:
x=`grep "\`dirname \"$path\"\`" file`
なぜなら
$()
引用符に対するまったく新しいコンテキストを強制するため、各コマンド置換は保護され、引用符やエスケープを特別に考慮することなく単独で処理できます。バッククォートを使用すると、2 レベル以上になるとどんどん醜くなります。さらにいくつかの例を示します:
echo `echo `ls`` # INCORRECT echo `echo \`ls\`` # CORRECT echo $(echo $(ls)) # CORRECT
これにより、バッククォートを使用する場合の一貫性のない動作の問題が解決されます。
echo '\$x'
出力\$x
echo `echo '\$x'`
出力$x
echo $(echo '\$x')
出力\$x
バックティック構文には、埋め込みコマンドの内容に関して歴史的な制限があり、バッククォートを含む一部の有効なスクリプトを処理できません。
$()
フォームは、あらゆる種類の有効な埋め込みスクリプトを処理できます。たとえば、これらの有効な埋め込みスクリプトは、左側の列では機能しませんが、右側の列では機能します。IEEE:
echo ` echo $( cat <<\eof cat <<\eof a here-doc with ` a here-doc with ) eof eof ` ) echo ` echo $( echo abc # a comment with ` echo abc # a comment with ) ` ) echo ` echo $( echo '`' echo ')' ` )
したがって、次の構文は $
-接頭辞付き コマンド置換 これは、きれいな構文で視覚的に明確で (人間と機械の可読性が向上します)、ネスト可能で直観的であり、内部解析が分離されており、(内部から解析される他のすべての拡張と) より一貫性があるため、推奨される方法です。二重引用符)、バッククォーテーションが唯一の例外であり、 `
キャラクターは隣接すると簡単にカモフラージュされます "
特に小さいフォントや珍しいフォントの場合、さらに読みにくくなります。
ソース: なぜですか $(...)
よりも好ましい `...`
(バッククォート)? Bashでよくある質問
以下も参照してください。
男BASHから:
$(command)
or
`command`
Bash performs the expansion by executing command and replacing the com-
mand substitution with the standard output of the command, with any
trailing newlines deleted. Embedded newlines are not deleted, but they
may be removed during word splitting. The command substitution $(cat
file) can be replaced by the equivalent but faster $(< file).
When the old-style backquote form of substitution is used, backslash
retains its literal meaning except when followed by $, `, or \. The
first backquote not preceded by a backslash terminates the command sub-
stitution. When using the $(command) form, all characters between the
parentheses make up the command; none are treated specially.
. 他の回答に加えて、
$(...)
.
より視覚的に立っている
`...`
.
バックトックはアポストロフィのように見えます。これは、使用しているフォントによって異なります。
(そして、私が気づいたように、バックトックはインラインコードサンプルに入るのが非常に難しいです。)
$()
ネストを許可します。
out=$(echo today is $(date))
バッククォートはそれを許可しないと思います。
を定義するのは POSIX 標準です。 $(command)
コマンド置換の形式。現在使用されているほとんどのシェルは POSIX に準拠しており、旧式のバッククォート表記よりもこの推奨形式をサポートしています。の コマンド置換 シェル言語ドキュメントのセクション (2.6.3) では、次のように説明されています。
コマンド置換を使用すると、コマンド名自体の代わりにコマンドの出力を置換できます。コマンド置換は、コマンドが次のように囲まれている場合に発生します。
$(指示)
または (逆引用符で囲まれたバージョン):
`指示`
シェルは次のコマンドを実行することでコマンド置換を拡張します。 指示サブシェル環境内 (を参照) シェル実行環境)およびコマンド代替の置換(のテキスト 指示 さらに、コマンドの標準出力を使用して「$()」またはバックコートを囲み、1つ以上のシーケンスを削除します
<newline>
代替の終わりにある文字。埋め込み<newline>
出力が終了する前の文字は削除されません。ただし、それらはフィールドデリミターとして扱われ、IFSの値に応じてフィールド分割中に排除される場合があります。出力にnullバイトが含まれている場合、動作は特定されていません。逆引用符で囲まれたスタイルのコマンド置換では、
<backslash>
次の場合を除き、その文字通りの意味を保持するものとします。'$
' , '`
'、 または<backslash>
. 。一致するバッククォートの検索は、最初の引用されていない非エスケープのバックロートによって満たされるものとします。この検索中に、シェルコメント、ここに埋め込まれたコマンドであるシェルコメント内で非エスケープのバッククォートが発生した場合($の埋め込みコマンド)指示)フォーム、または引用された文字列、未定義の結果が発生します。始まりますが、終了しない単一引用または二重引用文字列。`...`
「シーケンスは未定義の結果を生成します。$(指示)フォーム、一致する括弧への開かれた括弧に続くすべての文字は、 指示. 。有効なシェル スクリプトであればどれでも使用できます。 指示, 、不特定の結果を生成するリダイレクトのみで構成されるスクリプトを除きます。
コマンド代替の結果は、さらにチルドの拡張、パラメーター拡張、コマンド置換、または算術拡張のために処理されてはなりません。ダブルクォート内でコマンド置換が発生した場合、置換の結果に対してフィールド分割とパス名の拡張を実行してはなりません。
コマンド置換は入れ子にすることができます。バックコートされたバージョン内のネストを指定するには、アプリケーションは内部のバックコートの前に
<backslash>
キャラクター。例えば:
\`指示\`
シェルコマンド言語の構文には、「」で始まる展開に関してあいまいさがあります。
$((
「算術拡張またはサブシェルから始まるコマンド代替を導入できます。算術展開が優先されます。つまり、シェルは最初に拡張を算術拡張として解析できるかどうかを決定し、拡張を算術拡張として解析できないと判断した場合にのみ、拡張をコマンド置換として解析するものとします。シェルは、この決定を実行するときにネストされた展開を評価する必要はありません。拡張を算術拡張として解析できないとすでに判断せずに入力の終了に遭遇した場合、シェルは拡張を不完全な算術拡張として扱い、構文エラーを報告するものとします。適合するアプリケーションは、「」を確実に分離しなければなりません。$(
" そして '(
'サブシェルから始まるコマンド置換で、2つのトークン(つまり、それらを白い空間で分離)に入れます。たとえば、単一のサブシェルを含むコマンド置換は次のように記述できます。
$( (指示) )
これは遺産の質問ですが、私は$(...)
の上の`...`
の完全に有効な例を思い付きました。
私はCygwinを実行しているWindowsにリモートデスクトップを使用していて、コマンドの結果を繰り返したいと考えていました。残念ながら、リモートのデスクトップのものやCygwin自体のために、バックトックのキャラクターは入力不可能でした。
このような奇妙な設定をしてドル記号と括弧が入力する方が簡単になると仮定する。