シェルスクリプトの$ {}と$()の違い


28
$ echo $(date)
Thu Jul 2 16:33:11 SGT 2015
$ echo ${date}

$ name=foo
$ echo $(name)
ksh: name:  not found

$ echo ${name}
foo

$ {variable}は$ variableと同じようです。$()はコマンドを実行します。なぜ$ {}を使用するのですか?


回答:


39

$(command)「コマンド置換」です。あなたが理解しているように、それはを実行しcommand、その出力をキャプチャし、それを含むコマンドラインにそれを挿入し$(…)ます; 例えば、

$ ls -ld $(date +%B).txt
-rwxr-xr-x  1 Noob Noob    867 Jul  2 11:09 July.txt

${parameter}「パラメータ置換」です。多くの情報は、シェルのmanページbash(1)の「Parameter Expansion」という見出しの下にあります。

${parameter}
    パラメータ の値が置換されます。場合ブレースが必要とされるパラメータは、複数の桁との位置パラメータである場合、またはパラメータは、名前の一部として解釈されるべきではない文字が続きます。

位置パラメータについては、以下の「位置パラメータ」を参照してください。他の回答に示されているように、最も一般的な使用法 parameterは変数名です。${…}フォームは、上の段落の最後に述べたように、あなたは(すなわち、変数の値を取得することができます)、文字、数字、またはアンダースコアですぐにそれに従います。$variable_name

$ animal = cat
$ echo $ animals
                                「動物」などの変数はありません。
$ echo $ {animal} s
ねこ
$ echo $ animal_food
                                「animal_food」などの変数はありません。
$ echo $ {animal} _food
キャットフード

引用符でこれを行うこともできます:

$ echo "$ animal" s
ねこ

または、オプションの演習として、2番目の変数を使用できます。

$複数=
$ echo $ animal $ plural
ねこ

しかし、これはステップ1にすぎません。manページの次の段落は興味深いですが、少しわかりにくいです。

最初の文字の場合パラメータは、 感嘆符である(!)、変数間接のレベルが導入されます。Bashは、パラメーターの残りから形成された変数の値を変数 の名前として使用します。その後、この変数は展開され、その値はパラメーター自体の値ではなく、残りの置換で使用されます。これは間接展開として知られています。     (例外)    インダイレクションを導入するために、感嘆符は左中括弧の直後になければなりません。

例以外でこれをどのように明確にすることができるのか分かりません:

$ animal = cat
$ echo $ animal
ネコ
$ cat = tabby
$ echo $ cat
ぶち
$ echo $ {!animal}
tabby                             $ animal  “ cat”の場合、 $ {!animal}  $ cat 、つまり “ tabby”

したがって、そのステップを1½と呼びましょう。ステップ2でできることはたくさんあります。

$ animal = cat
$ echo $ {#animal}
3                                #ストリングの長さ
$ echo $ {animal / at / ow}
牛                              #置換

{... }括弧なしでは、これらのことはできません。

位置パラメータ

この人工的な例を考えてみましょう:

$猫myecho.sh
エコー$ 1 $ 2 $ 3 $ 4 $ 5 $ 6 $ 7 $ 8 $ 9 $ 10 $ 11 $ 12 $ 13 $ 14 $ 15
$ ./myecho.shねえ、ディドル・ディドル、猫とフィドル、牛が月を飛び越えました。
ねえディドル・ディドル、猫とフィドル、ねえ0ね1ね1ね2ね3ね4ね5

シェルは理解していないので$10$11それは扱いなど、$10それがであるかのように${1}0。しかし、それは理解して${10}${11}manページ(「複数の桁との位置パラメータ」)で述べたように、など、。

ただし、実際にそのようなスクリプトを作成しないでください。長い引数リストを処理するより良い方法があります。

上記の(より多くの形式の構成体と共に)シェルのmanページbash(1)でより長い時間で議論されています。${parameter…something_else}

引用に関する注意

シェル変数を引用するのは、正当な理由がない限り常に引用する必要があり、自分が何をしているのかを確実に把握していることに注意してください。対照的に、ブレースは重要ですが、引用符ほど重要ではありません。

$ filename = "nursery rhyme.txt"
$ ls -ld $ {ファイル名}
ls:ナーサリにアクセスできません:そのようなファイルまたはディレクトリはありません
ls:rhyme.txtにアクセスできません:そのようなファイルまたはディレクトリはありません
$ ls -ld "$ filename"
-rwxr-xr-x 1 Noob Noob 5309 7月2日11:09保育園rhyme.txt

これは、位置パラメータ(つまり、コマンドライン引数、例:)"$1"およびコマンド置換にも適用されます。

$ ls -ld $(date "+%B%Y")。txt
ls:7月にアクセスできません:そのようなファイルまたはディレクトリはありません
ls:2015.txtにアクセスできません:そのようなファイルまたはディレクトリはありません
$ ls -ld "$(date" +%B%Y ")。txt"
-rwxr-xr-x 1 Noob Noob 687 Jul 2 11:09 July 2015.txt

引用符と…の相互作用に関する簡潔な論文については、コマンド置換エスケープされていないBash引用符を参照してください。$()


素晴らしい例に感謝します。の使用について詳しく説明してください。あなたの例では。私はそれがどのように機能するか本当に理解していません。
-Noob

@Noob:OK、私はの使用について詳しく説明しました!
G-Manが「Reinstate Monica」と言う

ありがとう。どういうわけか!animalは、実際には値catではなく変数catを参照しています。また、echo $ {animal / at / ow}で/ atが "c"になる方法を教えてください。bashの男の説明はどういうわけか...わかりません。理解しにくい。
-Noob

また、このフレーズを詳しく説明してください-「$ {parameter} parameterの値は置換されます。」何で置き換えられますか?パラメーターがfruitで値がapple-fruit = appleの場合、$ {fruit}-appleは??に置き換えられます 本当にここに置換意味得ることはありません
Noobの

@Noob:「${!animal}実際$catには、値catの代わりに変数を参照しています。」はい、まさにそれがポイントです。「/ atはどのようにしてecho $ {animal / at / ow}の「c」になりますか?」/ atは「c」になりません。「cat」は、「at」が「ow」に置き換えられると「cow」になります。
G-Manが「Reinstate Monica」と言う

7

あなたの例では、$ varと$ {var}は同一です。ただし、文字列内の変数を展開する場合は、中括弧は便利です。

    $ string=foo
    $ echo ${string}bar
      foobar
    $ echo $stringbar

    $ 

したがって、中括弧は、置換される新しい変数の名前を取得するために変数を置換する手段を提供します。


4

私は通常、文字列でより一般的にそれを見ます。このようなものは機能しません:

var="a"
echo "$varRAW_STRING"

しかし、これは:

var="a"
echo "${var}RAW_STRING"

あなたが正しく言っ$()たように、コマンドを実行するために使用されます:

dir_contents=$(ls)

バックティックを使用することもできますが、$()より用途が広いと思います。1つには、バックティックを(簡単に)ネストすることはできません。

date_directory=`ls `date '+%Y-%m-%d'`` # Makes no sense
date_directory=$(ls $(date '+%Y-%m-%d')) # Much better

実際、バックティックネストできますdate_directory=`ls \`date '+%Y-%m-%d'\``。しかし、それはひどくいです。$(…)はるかに明確で使いやすいです。
G-Manは「Reinstate Monica」と言います

わかりました、結構です。それは技術的には可能ですが、私は誰もが今までだけであるため、読みやすさのそれをやって想像することはできません
bytesized

1
まあ、`…`だった前の年のためのコマンド置換のために(のみ)構文発明されたあなたは何を想像する必要はありませんので、 -人々はそれをやりました。$(…)
G-Manが「Reinstate Monica」と言う

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.