Зачем использовать двойные кавычки в тесте [[]]?

23

Допустим, у нас есть 2 целых числа в скрипте bash:

value1=5
value2=3

Тогда зачем нам использовать двойные кавычки в случае теста? Например:

if [[ "$value1" -eq "$value2" ]]

Почему бы просто не использовать следующее?

if [[ $value1 -eq $value2 ]]

Для меня двойные кавычки не имеют никакого смысла.

Meerkat
источник
5
Цитирование в оболочке не имеет ничего общего со строками (как в типах данных.) Это на самом деле о том, что оболочка не должна выполнять разбиение слов (и другие виды расширений.)
filbranden
13
Хотя, как указал тердон, нет необходимости слишком заключать в кавычки переменные в этой конкретной конструкции (и, разумеется, где-нибудь со значениями из одного слова), я бы хотел дать совет всегда заключать в кавычки ваши переменные. Вы действительно знаете, в каких контекстах вы можете оставить переменные без кавычек? Причина, по которой стоит цитировать, даже если это не обязательно с 5и 3, - ремонтопригодность. Значения могут измениться позже, и получающиеся ошибки могут не быть очевидными.
Питер - Восстановить Монику
2
@ Sudodus Я не думаю, что это правда [[ ]], только для [ ].
Бенджамин В.
1
Вы правы, @BenjaminW. Разделение слов - не единственный случай, когда рекомендуется использовать двойные кавычки для переменных. Существует также случай, когда переменная пуста. Это сделает оператор в [] неудачным (например, [2 -eq] с ошибкой, но [[]] не уязвим (как в случае с разделением слов).
sudodus
2
@marcelm, Bash, ksh и Zsh имеют целочисленные переменные, и в [[ ]]них они также приводят операнды -eqк целым числам.
ilkkachu

Ответы:

7

Разделение слов.

Этот пример очень маловероятен, но возможен , поэтому, если вы хотите защитить код, закройте ваши треки кавычками:

$ set -x
$ value1=5
+ value1=5
$ value2=3
+ value2=3
$ [ $value1 -eq $value2 ]
+ '[' 5 -eq 3 ']'

Хорошо, пока все хорошо. Давайте бросим гаечный ключ в шестеренки:

$ IFS=456
+ IFS=456
$ [ $value1 -eq $value2 ]
+ '[' '' -eq 3 ']'
bash: [: : integer expression expected

К сожалению.

$ [ "$value1" -eq "$value2" ]
+ '[' 5 -eq 3 ']'

Ааа.

Гленн Джекман
источник
2
Но OP использует двойные скобки, поэтому разделение слов не происходит.
user000001
5
Да, это не совсем относится к [[ ]]конструкции bash .
Тердон
1
А? [ $value1 -eq $value2 ]с пустым value1будет '[' -eq 3 ']'с нет ''на левой стороне.
Чарльз Даффи
Я тоже был удивлен, но есть доказательства.
Гленн Джекман
1
Этот ответ не имеет прямого отношения к вопросу. Я удивлен, что это было принято. Установка в качестве сообщества вики.
Гленн Джекман
35

Вам на самом деле не нужны цитаты здесь. Это один из немногих случаев, когда безопасно использовать переменную без кавычек. Вы можете подтвердить это с помощью set -x:

$ var1=""
$ var2="3"
$ set -x
$ if [[ $var1 -eq $var2 ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!
$ if [[ "$var1" -eq "$var2" ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!

Как вы можете видеть выше, версии теста в кавычках и без кавычек разрешаются в bash точно так же. То же самое должно быть верно и для zshлюбой другой оболочки, поддерживающей [[ ]]оператор.

Обратите внимание, что это не относится к более портативным [ ]:

$ if [ $var1 -eq $var2 ]; then echo "match!"; else echo "no match!"; fi
+ '[' -eq 3 ']'
sh: [: -eq: unary operator expected
+ echo 'no match!'
no match!

[ ]Конструкция, в отличие от [[ ]]одного, требует кавычек.


Некоторые полезные ссылки, чтобы узнать больше о том, когда и почему требуется цитирование:

Тердон
источник
В этом случае с целочисленными переменными было бы лучше объявить их как таковые. declare -i var1=это 0когда оценивается.
Фредди
4
Обратите внимание, что -eqэто арифметическое сравнение, так что вы можете даже оставить $out (in [[ .. ]]) и написать [[ a -eq b ]]. При сравнении строк нужно $, конечно, так[[ $a = $b ]]
ilkkachu
2
@ user000001 хороший момент. Хотя, конечно, очень возможно, что вы захотите расширить их. Например, я ожидаю, что это будет совпадение var1="afoob"; var2="a*b"; [[ $var1 = $var2 ]] && echo match. Если вы хотите использовать символы glob без их действия в качестве glob в контексте globbing (например, в [[ ]]), тогда вам нужно процитировать, да.
Тердон
3
@ilkkachu, это меня удивляет. Я думал, что «голые» переменные будут рассматриваться только в индексе массива или ((...))или $((...). Кажется, это работает, но (старый сварливый человек, включите), мне это не нравится.
Гленн Джекман
1
@glennjackman, ну, извините за то, что сказал вам это, но да, операнды -eqи друзья внутри [[ ]]тоже являются арифметическими контекстами. :) (Связано: автоматическое расширение переменных внутри команды bash [[]] )
ilkkachu
17

Хотя двойные кавычки не нужны, причины их использования:

  • Хорошая практика / привычка: В этом случае они не нужны, но в целом двойные кавычки являются , чтобы избежать непреднамеренного слова расщепления.
  • Потому что value1и value2являются переменными, и вы можете не знать, что они содержат. В противном случае вы могли бы также спросить: «Зачем беспокоиться о переменных, а не проверять if [[ 5 -eq 3 ]]? Или продолжать? Зачем ifвообще беспокоиться о том, когда вы уже знаете, что 5 не равно 3? Часто лучше защищаться». это разделение слов не произойдет [[, но случаи, когда разделение слов не происходит, редки. Опять же, смотрите первый пункт.)
jamesdlin
источник
1

Не имеет прямого отношения к вашему вопросу, но я использую

if (($ value1 == $ value2)); тогда

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

framp
источник
2
if (( value1 == value2 )); then, В арифметическом контексте вам даже не нужно $. Этот вопрос, однако, кажется, фокусируется на переменных, используемых в [[ ... ]]тестах.
Кусалананда
1
Я знаю. Но, честно говоря, я не использую эту функцию, потому что хочу, чтобы имена моих переменных были согласованными и, таким образом, все время использовали $ в качестве префикса.
Фрамп
1

Вы абсолютно правы!

Цитирование в двойных квадратных скобках не имеет никакого смысла, по крайней мере, в этом случае.

Но так как я использую двойные кавычки ежедневно - особенно для выражений в одной квадратной скобке, передачи аргументов функциям и сценариям, а также иногда для присваивания переменных (что совершенно бесполезно для простых делкакаций) - я предполагаю, что некоторые люди, по крайней мере, делают, писать двойные кавычки вокруг переменных расширения инстинктивно .

Двойное цитирование может дать вам чувство сохранности. Это как возвращаться домой, где двойные кавычки. - Д. Куммер

Преимущество выполнения двойных кавычек последовательно и понятно - но только в том смысле, в котором это имеет смысл - заключается в том, что коллеги, новички в bash, могут научиться писать более стабильные сценарии . Это также подчеркивает тот факт, что искусство обработки данных с помощью bash больше связано с разделением потоков данных (включая переменные) с помощью разделителей полей и передачей их через фильтры . Как только вы отделите свои блоки данных от потока, объедините их в двойные кавычки!

Еще одним преимуществом может быть лучшая читаемость сценариев bash со строками в двойных кавычках в редакторе с подсветкой кода .

Доминик Куммер
источник