22
$ 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. в то время как $() должен выполнить команду. Зачем тогда использовать $ {}?

3 ответа3

29

$(command) - это «подстановка команд».  Как вы, похоже, понимаете, она запускает command, записывает ее вывод и вставляет ее в командную строку, содержащую $(…) ; например,

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

${parameter} - это «подстановка параметров».  Много информации можно найти на странице руководства оболочки bash(1) под заголовком « Расширение параметров »:

${parameter}
    Значение параметра подставляется.  Скобки требуются, когда параметр является позиционным параметром с более чем одной цифрой, или когда за параметром следует символ, который не должен интерпретироваться как часть его имени.

Позиционные параметры см. В разделе « Позиционные параметры » ниже.  В его наиболее распространенном использовании, как показано в других ответах, parameter является именем переменной.  Форма ${…} , как указано в конце параграфа выше, позволяет вам получить значение переменной (т. Е. $variable_name) и сразу же следовать за ней с помощью буквы, цифры или подчеркивания:

$ animal=cat
$ echo $animals
                                # No such variable as “animals”.
$ echo ${animal}s
cats
$ echo $animal_food
                                # No such variable as “animal_food”.
$ echo ${animal}_food
cat_food

Вы также можете сделать это с кавычками:

$ echo "$animal"s
cats

Или, в качестве упражнения в опциях, вы можете использовать вторую переменную:

$ plural=s
$ echo $animal$plural
cats

Но это только первый шаг.  Следующий абзац на странице руководства интересен, хотя и немного загадочно:

Если первый символ параметра является восклицательным знаком (!), Вводится уровень косвенной косвенности.  Bash использует значение переменной, сформированной из остальной части параметра, в качестве имени переменной; эта переменная затем раскрывается, и это значение используется в остальной части замещения, а не в значении самого параметра.  Это известно как косвенное расширение.     (Исключения) Восклицательный знак должен следовать непосредственно за левой скобкой, чтобы ввести косвенное направление.

Я не уверен, как я могу сделать это понятнее, кроме как на примере:

$ animal=cat
$ echo $animal
cat
$ cat=tabby
$ echo $cat
tabby
$ echo ${!animal}
tabby                           # If $animal is “cat”, then ${!animal} is $cat, i.e., “tabby”

Итак, давайте назовем этот шаг 1½.  Есть много интересных вещей, которые вы можете сделать на шаге 2:

$ animal=cat
$ echo ${#animal}
3                               # String length
$ echo ${animal/at/ow}
cow                             # Substitution

Вы не можете делать ничего из этого без {} скобок.

Позиционные параметры

Рассмотрим этот искусственный пример:

$ cat myecho.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
$ ./myecho.sh Hey diddle diddle, The cat and the fiddle, The cow jumped over the moon.
Hey diddle diddle, The cat and the fiddle, The Hey0 Hey1 Hey2 Hey3 Hey4 Hey5

потому что оболочка не понимает $10, $11 и т. д. Она обрабатывает $10 как если бы это было ${1}0 .  Но он понимает ${10} , ${11} и т.д., Как упомянуто на странице руководства («позиционный параметр с более чем одной цифрой»).

Но на самом деле не пишите такие сценарии; Есть лучшие способы иметь дело с длинными списками аргументов.

Вышеупомянутое (наряду со многими другими формами конструкций ${parameter…something_else} ) более подробно обсуждается на странице руководства оболочки bash (1).

Примечание к цитатам

Обратите внимание, что вы всегда должны заключать в кавычки переменные оболочки, если у вас нет веских причин не делать этого, и вы уверены, что знаете, что делаете.  Напротив, хотя фигурные скобки могут быть важны, они не так важны, как кавычки.

$ filename="nursery rhyme.txt"
$ ls -ld ${filename}
ls: cannot access nursery: No such file or directory
ls: cannot access rhyme.txt: No such file or directory
$ ls -ld "$filename"
-rwxr-xr-x  1 Noob Noob   5309 Jul  2 11:09 nursery rhyme.txt

Это также относится к позиционным параметрам (т. Е. Аргументам командной строки; например, "$1"), а также к подстановке команд:

$ ls -ld $(date "+%B %Y").txt
ls: cannot access July: No such file or directory
ls: cannot access 2015.txt: No such file or directory
$ ls -ld "$(date "+%B %Y").txt"
-rwxr-xr-x  1 Noob Noob    687 Jul  2 11:09 July 2015.txt

См. Цитаты Bash, не экранированные при подстановке команд, для краткого трактата о взаимодействии между кавычками и $() .

6

В вашем примере $ var и $ {var} идентичны. Однако фигурные скобки полезны, когда вы хотите раскрыть переменную в строке:

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

    $ 

Таким образом, фигурные скобки обеспечивают возможность замены переменной, чтобы получить имя новой переменной, которая сама должна быть заменена.

3

Я обычно вижу это чаще в строках. Как то так не получится

var="a"
echo "$varRAW_STRING"

Но это будет:

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

Как вы правильно сказали, $() используется для выполнения команды:

dir_contents=$(ls)

Вы также можете использовать обратные пометки, но я считаю, что $() более универсален. Во-первых, обратные метки не могут быть (легко) вложенными.

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .