web-dev-qa-db-ja.com

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

$ 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と同じです。 $()はコマンドを実行します。なぜ$ {}を使うのですか?

23
Noob

$(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}
    の価値 パラメータ代入されます。括弧は次の場合に必要です。 パラメータ1桁以上の位置パラメータ、または パラメータその名前の一部として解釈されるべきではない文字が後に続きます。

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

$ animal = cat 
 $ echo $ animals 
 #そのような変数はありません "animals"。
 $ echo $ {animal} s 
 cats 
 $ echo $ animal_food 
 #そのような変数はありません "animal_food"。
 $ echo $ {animal} _food 
 cat_food

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

$ echo "$ animal" s 
猫

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

$ plural = s 
 $ echo $ animal $ plural 
 cats

しかし、これは単なるステップ1です。manページの次の段落は、ちょっとわかりにくいものの興味深いものです。

の最初の文字の場合 パラメータ 感嘆符(!)では、あるレベルの変数間接参照が導入されています。 Bashは残りの部分から形成された変数の値を使用します。 パラメータ 変数の名前として。次にこの変数が展開され、その値が代入の残りの部分で使用されます。 パラメータ 自体。これはとして知られています 間接拡張。 (例外)間接感を招くためには、感嘆符はすぐに左の括弧の後に続かなければなりません。

例を除いて、これをより明確にする方法がわかりません。

$ animal = cat 
 $ echo $ animal 
 cat 
 $ cat = tabby 
 $ echo $ cat 
 tabby 
 $ echo $ {!animal} 
 tabby #なら $動物 です "ネコ"それから $ {!動物} です $猫すなわち、 “タビー” 

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

$ animal = cat 
 $ echo $ {#animal} 
 3 #文字列の長さ
 $ echo $ {動物/ at/ow} 
牛 #代入

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

位置パラメータ

この人工的なの例を考えてください。

$ cat myecho.sh 
 echo $ 1 $ 2 $ 3 $ 4 $ 5 $ 6 $ 7 $ 8 $ 9 $ 10 $ 11 $ 12 $ 13 $ 14 $ 15 
 $ ./myecho.shちょっと戯れ、猫とフィドル、牛は飛び降りた
ちょっとしずくなね、猫とフィドル、ねえ0 Hey 1 Hey 2 Hey 3 Hey 4 Hey 5

シェルが$10$11などを理解していないためです。シェルは、$10${1}0のように扱います。しかし、manページに記載されているように${10}${11}などを理解します(「1桁以上の位置パラメータ」)。

しかし、実際にはそのようなスクリプトを書かないでください。長い引数リストを扱うためのより良い方法があります。

シェルのmanページの bash(1) で、上記(およびその他の${parameter…something_else}構造体の形式)について詳しく説明します。

引用についてのメモ

正当な理由がない限り、常にシェル変数を引用符で囲む必要があります。また、自分がしていることを知っていると確信しています。それとは対照的に、中括弧は重要ですが、引用符ほど重要ではありません。

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

これは位置パラメータ(コマンドライン引数、例えば"$1")やコマンド置換にも適用されます。

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

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

31
G-Man

あなたの例では、$ varと$ {var}は同一です。ただし、中括弧は、変数を文字列で展開したい場合に役立ちます。

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

    $ 

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

6
MariusMatutiae

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

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
3
bytesized