разница между $ {} и $ () в сценарии оболочки


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}это «подстановка параметров». Много информации можно найти на странице руководства оболочки bash (1) под заголовком « Расширение параметров »:

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

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

$ animal = cat
$ echo $ animals
                                # Нет такой переменной, как «животные».
$ echo $ {animal} s
коты
$ echo $ animal_food
                                # Нет такой переменной, как «animal_food».
$ echo $ {animal} _food
кошачья еда

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

$ echo "$ animal" s
коты

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

$ множественное число = с
$ echo $ animal $ множественное число
коты

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

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

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

$ animal = cat
$ echo $ animal
Кот
$ cat = табби
$ echo $ cat
полосатый
$ echo $ {! animal}
tabby                            # Если $ animal равно «cat» , то $ {! animal} равно $ cat , то есть «tabby»

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

$ animal = cat
$ echo $ {# animal}
3                                # длина строки
$ echo $ {animal / at / ow}
корова                              # замена

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

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

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

$ cat myecho.sh
эхо $ 1 $ 2 $ 3 $ 4 $ 5 $ 6 $ 7 $ 8 $ 9 $ 10 $ 11 $ 12 $ 13 $ 14 $ 15
$ ./myecho.sh Эй, диддл диддл, Кот и скрипка, Корова перепрыгнула через луну.
Эй диддл диддл, Кот и скрипка, Хей0 Хей1 Хей1 Хей3 Хей3 Хей4 Хей5

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

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

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

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

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

$ filename = "питомник rhyme.txt"
$ ls -ld $ {filename}
ls: не может получить доступ к питомнику: нет такого файла или каталога
ls: не может получить доступ к rhyme.txt: нет такого файла или каталога
$ ls -ld "$ filename"
-rwxr-xr-x 1 нуб нуб 5309 июл 2 11:09 детский стишок.txt

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

$ ls -ld $ (дата "+% B% Y"). txt
ls: нет доступа к июлю: нет такого файла или каталога
ls: невозможно получить доступ к 2015.txt: нет такого файла или каталога
$ ls -ld "$ (date" +% B% Y "). txt"
-rwxr-xr-x 1 Нуб Нуб 687 июл 2 11:09 июль 2015.txt

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


спасибо за прекрасный пример. Можете ли вы разработать использование! в вашем примере. Я не очень понимаю, как это работает.
Noob

@Noob: ОК, я подробно остановился на использовании !.
G-Man говорит: «Восстановите Монику»

Спасибо. Так или иначе! Animal фактически ссылается на переменную cat вместо значения cat. Можете ли вы также дать мне знать, как / at становится "c" в echo $ {animal / at / ow} Объяснение bash для человека так или иначе ... я не знаю. трудно понять.
Нуб

Кроме того, вы можете разработать эту фразу - "$ {параметр} Значение параметра подставляется." заменить чем? если параметром является фрукт, а его значением является яблоко - фрукт = яблоко, то $ {фрукты} - яблоко заменяется на ?? на самом деле значение здесь не подставляется
Noob

@Noob: « ${!animal}на самом деле ссылается на переменную, $catа не на значение cat». Да, в этом-то и дело. «Как / at становится« c »в echo $ {animal / at / ow}?» А? / at не становится "c"; «Кошка» становится «коровой», когда «у» заменяется на «ау».
G-Man говорит: «Восстановите Монику»

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)

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

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 говорит: «Восстановите Монику»

Хорошо, достаточно справедливо. Это технически возможно, но я не могу себе представить, чтобы кто-то делал это только из-за читабельности
байтово

1
Ну, `…`был (только) синтаксис для подстановки команд в течение многих лет , прежде чем был изобретен, так что вам не нужно представить ничего - люди сделали это. $(…)
G-Man говорит: «Восстановите Монику»

s / когда-либо делает это / делает это больше /
bytesized
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.