Ссылки на переменные в сценарии оболочки


10

В сценарии оболочки, если я определяю переменную, такую ​​как FOO=25, есть ли разница между ссылками на нее как $FOO$и ${FOO}$?


2
Вы не должны использовать $в конце концов! Он будет обрабатываться как обычный символ, а не как часть имени переменной.
Byte Commander

Ответы:


16

В большинстве ситуаций оба $varи ${var}одинаковы. (Обратите внимание, что вы не должны использовать $в конце!)

Один пример, где вам нужны фигурные скобки, - это когда вам нужно поместить переменную в непрерывную строку.

Пример:

var=hel
echo ${var}lo

будет выводить hello.


11

Чтобы ответить на ваш главный вопрос, ${foo}это называется «расширение параметров» . Чтобы быть точным, $сам запускает расширение параметров, { }они на самом деле необязательны в соответствии со спецификацией POSIX , но могут быть полезны для указания конца имени переменной:

$ foo="bar"
$ echo $fooBaz   ## fails, no variable named $fooBaz exists

$ echo ${foo}Baz ## works, $foo is expanded and the string Baz is appended
barBaz

В основном $fooи ${foo}идентичны. За исключением случаев, подобных описанному выше, или когда вы выполняете манипуляции со строками , они полностью эквивалентны.

Тем не менее, вы не должны использовать ни один из них. Эмпирическое правило заключается в том, что, за очень немногими исключениями, вы должны всегда использовать "$foo"или "${foo}"и никогда $fooили ${foo}. Вы всегда должны заключать в кавычки свои переменные, чтобы избежать вызова оператора split + glob (подробнее об этом позже). Вы, конечно, не хотите $foo$. Финал не $имеет значения:

$ foo="bar"
$ echo "$foo$"
bar$

Итак, в то время как переменные без кавычек иногда в порядке:

$ echo $foo
bar

Их обычно нет, и их действительно следует избегать:

$ if [ -n $foo ]; then echo empty; else echo "not empty"; fi ## fails
empty

$ if [ -n "$foo" ]; then echo empty; else echo "not empty"; fi ## works
not empty

Обратите внимание, что скобки здесь тоже не помогают:

$ if [ -n ${foo} ]; then echo empty; else echo "not empty"; fi  ## fails
empty

$ if [ -n "${foo}" ]; then echo empty; else echo "not empty"; fi ## works
not empty

Когда вы используете $fooили ${foo}, оболочка разделяет значение, сохраненное в переменной на пустое пространство (это можно изменить, установив IFSпеременную в другое значение), в список, а затем каждый элемент списка обрабатывается как глобальный шаблон и разворачивается в любые соответствующие файлы или каталоги. Это известно как оператор split + glob . Для иллюстрации рассмотрим каталог с двумя файлами:

$ ls -l
-rw-r--r-- 1 terdon terdon 0 Oct  9 18:16 file1
-rw-r--r-- 1 terdon terdon 0 Oct  9 18:16 file2

Теперь давайте установим переменную в foo *:

$ foo="foo *"

Что произойдет, если мы попытаемся проверить, существует ли файл с таким именем?

$ if [ -e $foo ]; then echo "file exists"; else echo "no such file"; fi
file exists

Переменная была разбита на fooи *и, поскольку *это подстановочный знак, который соответствует любой строке, оболочка сообщает вам, что файл называется foo *exxists. Однако, если мы процитируем это правильно, этого не произойдет:

$ if [ -e "$foo" ]; then echo "file exists"; else echo "no such file"; fi
no such file

Это был тривиальный пример, чтобы проиллюстрировать это. Представь, если бы я использовал rmвместо этого, echoхотя.

Итак, первое правило: всегда указывайте свои переменные. Вы можете использовать либо "$foo"или, "${foo}"но процитировать его в любом случае. Чтобы узнать больше о безопасном использовании переменных, взгляните на эти сообщения:


Я не хотел редактировать ваш отличный ответ, но не должен $ var="foo *"ли $ foo="foo *"? Вы не используете varнигде.
Джо

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