Я читал, что вам нужны двойные кавычки для расширения переменных, например
if [ -n "$test" ]; then echo '$test ok'; else echo '$test null'; fi
будет работать как положено, пока
if [ -n $test ]; then echo '$test ok'; else echo '$test null'; fi
всегда будет говорить, $test ok
даже если $test
это ноль.
но тогда почему нам не нужны кавычки echo $test
?
echo
, лишние пробелы и символы новой строки будут удалены.Ответы:
Вам всегда нужны кавычки вокруг переменных во всех контекстах списка , то есть везде, где переменная может быть расширена до нескольких значений, если вы не хотите, чтобы 3 побочных эффекта оставляли переменную без кавычек.
списочные контексты включают в себя аргументы для простых команд, таких как,
[
илиecho
,for i in <here>
присваивания массивам ... Существуют и другие контексты, в которых переменные также должны заключаться в кавычки. Лучше всего всегда заключать в кавычки переменные, если у вас нет веских причин не делать этого.Думайте об отсутствии кавычек (в контексте списка) как оператора split + glob .
Как будто
echo $test
былecho glob(split("$test"))
.Поведение оболочки сбивает с толку большинство людей, потому что в большинстве других языков вы помещаете кавычки вокруг фиксированных строк, например
puts("foo")
, а не вокруг переменных (напримерputs(var)
), в то время как в оболочке все наоборот: все является строкой в оболочке, так что кавычки вокруг всего было бы обременительно, вамecho test
, вам не нужно"echo" "test"
. В оболочке кавычки используются для чего-то другого: предотвращают какое-то особое значение некоторых символов и / или влияют на поведение некоторых расширений.В
[ -n $test ]
илиecho $test
оболочка разделится$test
(по умолчанию на пустые места), а затем выполнит генерацию имени файла (развернет все*
шаблоны '?' ... до списка подходящих файлов), а затем передаст этот список аргументов командам[
илиecho
,Опять же, подумайте об этом как
"[" "-n" glob(split("$test")) "]"
. Если$test
оно пустое или содержит только пробелы (spc, tab, nl), то оператор split + glob вернет пустой список, поэтому[ -n $test ]
будет"[" "-n" "]"
, который проверяет, является ли «-n» пустой строкой или нет. Но представьте, что случилось бы, если бы$test
было "*" или "= foo" ...В
[ -n "$test" ]
,[
передаются четыре аргумента"["
,"-n"
,""
и"]"
(без кавычек), который является то , что мы хотим.Независимо от того, имеет это значение
echo
или[
нет, простоecho
выводит одно и то же, независимо от того, был ли передан пустой аргумент или нет аргумента вообще.Смотрите также этот ответ на аналогичный вопрос для более подробной информации о
[
команде и[[...]]
конструкции.источник
Ответ @ h3rrmiller хорош для объяснения, почему вам нужны кавычки для
if
(или, скорее,[
/test
), но я бы на самом деле предположил, что ваш вопрос неверен.Попробуйте следующие команды, и вы поймете, что я имею в виду.
Без кавычек подстановка переменных приводит к расширению второй команды до:
и несколько пробелов свернуты в один:
С кавычками пробелы сохраняются.
Это происходит потому , что , когда вы цитируете параметр (независимо от того , что передаваемый параметр
echo
,test
или какой -либо другой команды), то значение этого параметра передается в качестве одного значения к команде. Если вы не заключите его в кавычки, оболочка выполняет обычную магию поиска пробелов, чтобы определить, где начинается и заканчивается каждый параметр.Это также может быть проиллюстрировано следующей (очень очень простой) C-программой. Попробуйте выполнить следующую команду в командной строке (вы можете сделать это в пустой директории, чтобы не рисковать перезаписью чего-либо).
а потом...
После бега
paramtest
,$?
проведет ряд параметров он был принят (и это число будет напечатано).источник
Это все о том, как оболочка интерпретирует строку перед выполнением программы.
Если строка читается
echo I am $USER
, оболочка раскрывает ееecho I am blrfl
иecho
не имеет понятия, является ли источник текста литералом или переменным расширением. Точно так же, если строка читаетecho I am $UNDEFINED
, оболочка не расширится$UNDEFINED
до нуля, и аргументы echo будутI am
, и на этом все. Так какecho
работает просто отлично без аргументов,echo $UNDEFINED
полностью действителен.Ваша проблема с
if
не действительноif
, потому чтоif
просто запускает любую программу и аргументы, которые следуют за ней, и выполняетthen
часть, если программа выходит0
(илиelse
часть, если она есть, и программа выходит из non-0
):Когда вы используете
if [ ... ]
для сравнения, вы не используете примитивы, встроенные в оболочку. Вы на самом деле инструктируете оболочку для запуска программы,[
которая называется очень небольшой надмножество, дляtest(1)
которого требуется последний аргумент]
. Обе программы завершаются,0
если условие теста выполнилось, а1
если нет.Причина, по которой некоторые тесты ломаются, когда переменная не определена, заключается в том, что
test
она не видит, что вы используете переменную. Ergo,[ $UNDEFINED -eq 2 ]
ломается, потому что к тому времени, когда оболочка работает с ней, всеtest
видит аргументы-eq 2 ]
, что не является допустимым тестом. Если вы сделали это с чем-то определенным, например[ $DEFINED -ne 0 ]
, это сработало бы, потому что оболочка превратила бы его в действительный тест (например,0 -ne 0
).Существует семантическая разница между ними
foo $UNDEFINED bar
, которая расширяется до двух аргументов (foo
иbar
), поскольку$UNDEFINED
соответствует своему названию. Сравните это сfoo "$UNDEFINED" bar
, который расширяется до трех аргументов (foo
пустая строка и `bar). Кавычки заставляют оболочку интерпретировать их как аргумент, есть ли что-то между ними или нет.источник
Без кавычек
$test
можно расширить до более чем одного слова, поэтому его нужно заключать в кавычки, чтобы не нарушать синтаксис, поскольку каждый переключатель внутри[
команды ожидает один аргумент, который делает кавычки (превращает все, что$test
расширяется в один аргумент)Причина, по которой вам не нужны кавычки для расширения переменной,
echo
заключается в том, что она не ожидает одного аргумента. Он просто напечатает то, что вы говорите. Так что, даже если$test
расшириться до 100 слов, эхо все равно напечатает егоВзгляните на Bash Pitfalls
источник
echo
?echo
. Что заставляет вас думать иначе?echo $test
и это работает (выводит значение $ test)Пустые параметры удаляются, если не указаны:
Вызываемая команда не видит, что в командной строке оболочки был пустой параметр. Похоже, что [определено так, что оно возвращает 0 для -n, но ничего не следует. Whyever.
Цитирование также имеет значение для эха, в некоторых случаях:
источник
echo
, это оболочка. Вы бы увидели такое же поведение сls
. Попробуйтеtouch '*'
некоторое время, если вы чувствуете себя авантюрным.:)