226

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

  1. レガシーボーンシェルバックティック``

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

    var=$(command)
    

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

4

9 に答える 9

217

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

例:多少工夫されていますが:

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

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

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

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

(a)特定のコマンドが実際に機能しない可能があるため、機能をテストしていません。ですから、私に反対票を投じると、その意図を見失ってしまいます:-)これは、バグのない本番環境に対応したスニペットではなく、ネストする方法を示すためのものです。

于 2012-02-26T01:40:13.797 に答える
75

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

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

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

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

于 2012-02-26T02:03:04.913 に答える
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コマンド置換の構文は、クリーンな構文で視覚的に明確であり(人間とマシンの可読性が向上)、ネスト可能で直感的であり、内部解析が分離されており、より一貫性があるため(バッククォート内から解析される他のすべての展開)は、バッククォートが唯一の例外であり、特に小さいフォントや珍しいフォントでは、`文字が隣接していると簡単にカモフラージュ"されて読みにくくなります。

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

参照:

于 2015-10-23T11:36:50.517 に答える
27

マンバッシュから:

       $(コマンド)
また
       `コマンド`

Bashは、コマンドを実行し、com-を置き換えることによって拡張を実行します。
コマンドの標準出力でのmand置換、
末尾の改行が削除されました。埋め込まれた改行は削除されませんが、
単語分割中に削除される場合があります。コマンド置換$(cat
file)は、同等ですがより高速な$(<file)に置き換えることができます。

古いスタイルのバッククォート形式の置換を使用する場合は、バックスラッシュ
$、 `、または\が続く場合を除いて、文字通りの意味を保持します。The
バックスラッシュが前に付いていない最初のバッククォートは、コマンドサブを終了します。
制度。$(コマンド)フォームを使用する場合、
括弧はコマンドを構成します。特別に扱われるものはありません。
于 2012-02-26T01:41:59.467 に答える
11

他の答えに加えて、

$(...)

視覚的に目立つ

`...`

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

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

于 2012-02-26T01:58:27.023 に答える
9

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

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

バックティックはそれを許可しないと思います。

于 2012-02-26T01:44:03.890 に答える
5

It is the POSIX standard that defines the $(command) form of command substitution. Most shells in use today are POSIX compliant and support this preferred form over the archaic backtick notation. The command substitution section (2.6.3) of the Shell Language document describes this:

Command substitution allows the output of a command to be substituted in place of the command name itself.  Command substitution shall occur when the command is enclosed as follows:

$(command)

or (backquoted version):

`command`

The shell shall expand the command substitution by executing command in a subshell environment (see Shell Execution Environment) and replacing the command substitution (the text of command plus the enclosing "$()" or backquotes) with the standard output of the command, removing sequences of one or more <newline> characters at the end of the substitution. Embedded <newline> characters before the end of the output shall not be removed; however, they may be treated as field delimiters and eliminated during field splitting, depending on the value of IFS and quoting that is in effect. If the output contains any null bytes, the behavior is unspecified.

Within the backquoted style of command substitution, <backslash> shall retain its literal meaning, except when followed by: '$' , '`', or <backslash>. The search for the matching backquote shall be satisfied by the first unquoted non-escaped backquote; during this search, if a non-escaped backquote is encountered within a shell comment, a here-document, an embedded command substitution of the $(command) form, or a quoted string, undefined results occur. A single-quoted or double-quoted string that begins, but does not end, within the "`...`" sequence produces undefined results.

With the $(command) form, all characters following the open parenthesis to the matching closing parenthesis constitute the command. Any valid shell script can be used for command, except a script consisting solely of redirections which produces unspecified results.

The results of command substitution shall not be processed for further tilde expansion, parameter expansion, command substitution, or arithmetic expansion. If a command substitution occurs inside double-quotes, field splitting and pathname expansion shall not be performed on the results of the substitution.

Command substitution can be nested. To specify nesting within the backquoted version, the application shall precede the inner backquotes with <backslash> characters; for example:

\`command\`

The syntax of the shell command language has an ambiguity for expansions beginning with "$((", which can introduce an arithmetic expansion or a command substitution that starts with a subshell. Arithmetic expansion has precedence; that is, the shell shall first determine whether it can parse the expansion as an arithmetic expansion and shall only parse the expansion as a command substitution if it determines that it cannot parse the expansion as an arithmetic expansion. The shell need not evaluate nested expansions when performing this determination. If it encounters the end of input without already having determined that it cannot parse the expansion as an arithmetic expansion, the shell shall treat the expansion as an incomplete arithmetic expansion and report a syntax error. A conforming application shall ensure that it separates the "$(" and '(' into two tokens (that is, separate them with white space) in a command substitution that starts with a subshell. For example, a command substitution containing a single subshell could be written as:

$( (command) )

于 2012-02-26T13:53:50.713 に答える
5

$(...)私はoverの完全に有効な例を思いついた`...`

Cygwinを実行しているWindowsへのリモートデスクトップを使用していて、コマンドの結果を反復処理したいと思いました。悲しいことに、リモートデスクトップの問題またはCygwin自体のいずれかが原因で、バッククォート文字を入力できませんでした。

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

于 2015-12-04T11:10:48.487 に答える
1

ここ2021年に、他の回答の補足として奇妙な事実に言及する価値があります。

パイプライン用のMicrosoftDevOpsYAML 「スクリプト」には、Bashタスク 含まれる場合があります。ただし、この表記はYAMLコンテキストで定義された変数を参照するために使用されるため、この場合、コマンドの出力をキャプチャするためにバッククォートを使用する必要があります。$()

DevOpsプリプロセッサは存在しない変数について非常に寛容であるため、これはスクリプトコードをYAMLスクリプトにコピーするときに主に問題になり、エラーメッセージは表示されません。

于 2021-03-11T13:36:18.163 に答える