web-dev-qa-db-ja.com

シェルスクリプトでバックティックの代わりに$()を使用する利点は何ですか?

bashでコマンドラインの出力をキャプチャするには、2つの方法があります。

  1. レガシーBourne Shellバックティック``

     var=`command`
    
  2. $()構文(私が知る限り、Bash固有のものであるか、少なくとも元のBourneのような非POSIX古いシェルではサポートされていません)

     var=$(command)
    

バッククォートと比較して2番目の構文を使用する利点はありますか?または、2つは完全に100%同等ですか?

142
DVK

主なものは、nestそれら、コマンド内のコマンド、バックティックで何らかのエスケープが機能するかどうかを判断しようとする正気を失うことなく、それらの機能です。

多少不自然ですが、例:

deps=$(find /dir -name $(ls -1tr 201112[0-9][0-9]*.txt | tail -1l) -print)

これにより、2011年12月の最も古い日付のテキストファイルと同じ名前を持つ/dirディレクトリツリー内のすべてのファイルのリストが表示されます。 (a)

別の例は、親ディレクトリの名前(フルパスではなく)を取得するようなものです。

pax> cd /home/pax/xyzzy/plugh
pax> parent=$(basename $(dirname $PWD))
pax> echo $parent
xyzzy

(a) specificコマンドが実際に機能しない可能性があるため、機能をテストしていません。だから、もしあなたが私に賛成票を投じると、その意図を見失ってしまいます:-)これは、バグのない本番用のスニペットとしてではなく、単にネストする方法を説明するためのものです。

134
paxdiablo

gccがインストールされている場所に対応するlibディレクトリを検索するとします。次の選択肢があります。

libdir=$(dirname $(dirname $(which gcc)))/lib

libdir=`dirname \`dirname \\\`which gcc\\\`\``/lib

最初の方が2番目よりも簡単です-最初の方を使用してください。

50

バックティック(`...`)は、非常に古い非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およびdashでは必要ないため、移植性はありません。

  • ネストされたコマンド置換の構文は簡単です:

    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
  • Backticks構文には埋め込みコマンドの内容に歴史的な制限があり、バッククォートを含む有効なスクリプトを処理できませんが、新しい$()フォームはあらゆる種類の有効な埋め込みスクリプトを処理できます。

    たとえば、そうでなければ有効な埋め込みスクリプトは左の列では機能しませんが、右の列では機能します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 ')'
    `                              )
    

したがって、$- prefixed command substitution の構文は、きれいな構文で視覚的に明確であり(人間と機械の可読性が向上する)、ネスト可能で直感的であるため、推奨される方法です。解析は独立しており、バッククォートが唯一の例外であり、`に隣接しているときに"文字が簡単に偽装されている(二重引用符内から解析される他のすべての展開と)より一貫性があります特に小さなフォントや珍しいフォントでは、さらに読みにくくなります。

ソース: なぜ$(...)`...`(バックティック)よりも優先されるのですか? BashFAQ

こちらもご覧ください:

26
kenorb

Man 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.
21
dgw

他の答えに加えて、

$(...)

より視覚的に優れている

`...`

バックティックはアポストロフィのように見えます。これは、使用しているフォントによって異なります。

(そして、先ほど気づいたように、バックコードはインラインコードサンプルに入力するのがはるかに困難です。)

9
Keith Thompson

$()はネストを許可します。

out=$(echo today is $(date))

バックティックでは許可されていないと思います。

6
Shiplu Mokaddim

これは従来の質問ですが、$(...) over `...`の完全に有効な例を思い付きました。

私はcygwinを実行しているウィンドウにリモートデスクトップを使用していましたが、コマンドの結果を反復処理したかったのです。悲しいことに、リモートデスクトップの問題またはcygwin自体のいずれかにより、バックティックキャラクターを入力することはできませんでした。

このような奇妙な設定では、ドル記号と括弧を入力する方が簡単だと想定するのは正気です。

3

コマンド置換の$(command)形式を定義するのはPOSIX標準です。現在使用されているほとんどのシェルはPOSIXに準拠しており、古風なバックティック表記よりもこの好ましい形式をサポートしています。これについては、シェル言語ドキュメントの コマンド置換 セクション(2.6.3)で説明されています。

コマンド置換を使用すると、コマンド名自体の代わりにコマンドの出力を置換できます。コマンド置換は、コマンドが次のように囲まれている場合に発生します。

$(command)

または(バッククォートされたバージョン):

`command`

シェルは、サブシェル環境( Shell Execution Environment を参照)でcommandを実行し、コマンド置換を置き換えることにより、コマンド置換を拡張します。 (commandのテキストと、囲む「$()」または逆引用符)、コマンドの標準出力、1つ以上の<newline>文字のシーケンスの削除置換の最後。出力の最後の前に埋め込まれた<newline>文字は削除されません。ただし、有効なIFSおよび引用符の値によっては、フィールド区切り文字として扱われ、フィールド分割中に削除される場合があります。出力にヌルバイトが含まれる場合、動作は指定されません。

コマンド置換の逆引用符付きスタイル内で、<backslash>は、「$」、「`」、または<backslash>が後に続く場合を除き、リテラルの意味を保持します。一致するバッククォートの検索は、最初のクォートされていないエスケープされていないバッククォートによって満たされます。この検索中に、シェルコメント、ヒアドキュメント、$(command)の埋め込みコマンド置換内でエスケープされていない逆引用符が検出された場合フォーム、または引用符付き文字列、未定義の結果が発生します。 「`...`」シーケンス内で始まるが終了しない単一引用符または二重引用符で囲まれた文字列は、未定義の結果を生成します。

$(command)形式では、開き括弧から対応する閉じ括弧までのすべての文字がcommand。任意の有効なシェルスクリプトをcommandに使用できますが、不特定の結果を生成するリダイレクトのみで構成されるスクリプトを除きます。

コマンド置換の結果は、さらにチルダ展開、パラメーター展開、コマンド置換、または算術展開のために処理されません。二重引用符内でコマンドの置換が発生した場合、置換の結果に対してフィールド分割とパス名拡張は実行されません。

コマンド置換はネストできます。逆引用符付きバージョン内でネストを指定するには、アプリケーションは<backslash>文字を内部逆引用符の前に置く必要があります。例えば:

\`command\`

シェルコマンド言語の構文には、「$((」で始まる展開のあいまいさがあり、算術展開またはサブシェルで始まるコマンド置換を導入できます。算術展開が優先されます。つまり、シェルはまず、展開を算術展開として解析できるかどうかを判断し、展開を算術展開として解析できないと判断した場合にのみ、コマンド置換として展開を解析します。この決定を実行するときに、シェルはネストされた展開を評価する必要はありません。展開を算術展開として解析できないと判断せずに入力の終わりに到達した場合、シェルは展開を不完全な算術展開として扱い、構文エラーを報告します。適合アプリケーションは、サブシェルで始まるコマンド置換で、「$(」と「(」を2つのトークンに分離する(つまり、スペースで分離する)ことを保証する必要があります。たとえば、単一のサブシェルを含むコマンド置換は、次のように記述できます。

$( (command) )

2
JRFerguson