Этот вопрос содержит много дубликатов, многие из которых не связаны с переменными, поэтому я переименовал «значение» вместо «переменная». Я надеюсь, что это поможет большему количеству людей найти эту тему.
tripleee
1
@codeforester Что случилось с отмененным редактированием?
Общее правило: заключите его в кавычки, если оно может быть пустым или содержать пробелы (или любые пробельные символы) или специальные символы (подстановочные знаки). Не цитирование строк с пробелами часто приводит к тому, что оболочка разбивает один аргумент на множество.
$?кавычки не нужны, так как это числовое значение. Если $URLнеобходимо , это зависит от того, что вы позволяете там и по- прежнему хотите ли вы аргумент , если он пуст.
Я склонен всегда цитировать строки просто по привычке, потому что так безопаснее.
Обратите внимание, что «пробелы» действительно означают «любые пробелы».
Уильям Перселл
4
@Cristian: Если вы не уверены, что может быть в переменной, безопаснее заключить ее в кавычки. Я склонен следовать тому же принципу, что и paxdiablo, и просто привыкаю цитировать все (если нет особых причин не делать этого).
Гордон Дэвиссон
11
Если вы не знаете значение IFS, укажите его, несмотря ни на что. Если IFS=0, то echo $?может быть очень удивительно.
Чарльз Даффи
3
Цитируйте, основываясь на контексте, а не на ожидаемых значениях, иначе ваши ошибки будут хуже. Например, вы уверены , что ни один из путей не имеют места, так что вы думаете , что вы можете написать cp $source1 $source2 $dest, но если по какой - то непредвиденной причине destне делает приготовьтесь, третий аргумент просто исчезает, и он будет молча копировать source1через source2вместо давая вам соответствующая ошибка для пустого места назначения (как если бы вы указали каждый аргумент).
Дерек Вейт
3
quote it if...мыслительный процесс задом наперед - кавычки - это не то, что вы добавляете, когда нужно, а то, что вы удаляете, когда это необходимо. Всегда заключайте строки и сценарии в одинарные кавычки, если только вам не нужно использовать двойные кавычки (например, чтобы разрешить расширение переменной) или вам не нужно использовать кавычки (например, чтобы выполнять глобализацию и расширение имени файла).
Эд Мортон
92
Вкратце, процитируйте все, где вам не требуется оболочка для разделения токенов и подстановочных знаков.
Одинарные кавычки защищают текст между ними дословно. Это подходящий инструмент, когда вам нужно убедиться, что оболочка вообще не касается строки. Как правило, это предпочтительный механизм цитирования, когда вам не требуется переменная интерполяция.
$ echo 'Nothing \t in here $will change'Nothing \t in here $will change
$ grep -F '@&$*!!' file /dev/null
file:I can't get this @&$*!! quoting right.
Двойные кавычки подходят, когда требуется переменная интерполяция. С подходящими адаптациями это также хороший обходной путь, когда вам нужны одинарные кавычки в строке. (Не существует простого способа избежать одиночной кавычки между одинарными кавычками, потому что в одинарных кавычках нет механизма перехода - если бы он был, они бы не цитировали полностью дословно.)
$ echo "There is no place like '$HOME'"There is no place like '/home/me'
Никакие кавычки не подходят, когда вам конкретно требуется, чтобы оболочка выполняла разбиение токена и / или расширение по шаблону.
Расщепление токенов;
$ words="foo bar baz"
$ for word in $words;do> echo "$word">done
foo
bar
baz
В отличие от:
$ for word in"$words";do echo "$word";done
foo bar baz
(Цикл выполняется только один раз над строкой в кавычках.)
$ for word in'$words';do echo "$word";done
$words
(Цикл выполняется только один раз, над литеральной строкой в одинарных кавычках.)
Расширение подстановочного знака:
$ pattern='file*.txt'
$ ls $pattern
file1.txt file_other.txt
В отличие от:
$ ls "$pattern"
ls: cannot access file*.txt:No such file or directory
(Там нет файла с именем буквально file*.txt.)
$ ls '$pattern'
ls: cannot access $pattern:No such file or directory
(Нет файла с именем $pattern тоже нет!)
В более конкретных терминах все, что содержит имя файла, обычно должно заключаться в кавычки (поскольку имена файлов могут содержать пробелы и другие метасимволы оболочки). Все, что содержит URL, обычно следует заключать в кавычки (поскольку многие URL содержат метасимволы оболочки, такие как ?и& ). Все, что содержит регулярное выражение, обычно должно быть заключено в кавычки (то же самое). Все, что содержит значительные пробелы, кроме одинарных пробелов между непробельными символами, должно быть заключено в кавычки (потому что в противном случае оболочка перебирает пробельные символы в эффективные одиночные пробелы и обрезает любые начальные или конечные пробельные символы).
Когда вы знаете, что переменная может содержать только значение, которое не содержит метасимволов оболочки, заключение в кавычки необязательно. Таким образом, без кавычек $?в основном нормально, потому что эта переменная может содержать только одно число. Тем не мение,"$?" это также правильно, и рекомендуется для общей последовательности и правильности (хотя это моя личная рекомендация, а не общепризнанная политика).
Значения, которые не являются переменными, в основном следуют тем же правилам, хотя вы можете также избегать любых метасимволов вместо того, чтобы заключать их в кавычки. В типичном примере URL-адрес, содержащий &в нем, будет обрабатываться оболочкой как фоновая команда, если метасимвол не экранирован или не заключен в кавычки:
$ wget http://example.com/q&uack
[1] wget http://example.com/q
-bash: uack: command not found
(Конечно, это также происходит, если URL-адрес находится в переменной без кавычек.) Для статической строки наиболее целесообразно использовать одинарные кавычки, хотя любая форма цитирования или экранирования здесь работает.
wget 'http://example.com/q&uack'# Single quotes preferred for a static string
wget "http://example.com/q&uack"# Double quotes work here, too (no $ or ` in the value)
wget http://example.com/q\&uack # Backslash escape
wget http://example.com/q'&'uack # Only the metacharacter really needs quoting
Последний пример также предлагает другую полезную концепцию, которую я люблю называть «цитатами на качелях». Если вам нужно смешать одинарные и двойные кавычки, вы можете использовать их рядом друг с другом. Например, следующие строки в кавычках
'$HOME '"isn't"' where `<3'"' is."
могут быть вставлены вместе, образуя одну длинную строку после токенизации и удаления кавычек.
$ echo '$HOME '"isn't"' where `<3'"' is."
$HOME isn't where `<3' is.
Это не очень разборчиво, но это обычная техника и поэтому полезно знать.
$ printf '%s\n' $pattern # not ``ls -1 $pattern''
file1.txt
file_other.txt
$ for file in $pattern;do# definitely, definitely not ``for file in $(ls $pattern)''> printf 'Found file: %s\n'"$file">doneFound file: file1.txt
Found file: file_other.txt
(Цикл совершенно лишний в последнем примере; printfособенно хорошо работает с несколькими аргументами.stat Также. Но зацикливание на совпадении с подстановочными знаками является обычной проблемой, и часто выполняется неправильно.)
Переменная, содержащая список токенов для зацикливания или подстановочный знак для расширения, встречается реже, поэтому мы иногда сокращаем, чтобы «заключить в кавычки все, если вы точно не знаете, что делаете».
Это вариант ответа (части), который я разместил на соответствующий вопрос . Я вставляю это здесь, потому что это сжато и достаточно четко определено, чтобы стать каноническим вопросом для этой конкретной проблемы.
tripleee
4
Отмечу, что это пункт № 0 и повторяющаяся тема в коллекции распространенных ошибок Bash mywiki.wooledge.org/BashPitfalls . Многие, многие из отдельных пунктов в этом списке в основном об этой проблеме.
tripleee
27
Вот трехточечная формула для цитат в целом:
Двойные кавычки
В тех случаях, когда мы хотим подавить разбиение и сглаживание слов. Также в тех случаях, когда мы хотим, чтобы литерал обрабатывался как строка, а не как регулярное выражение.
Одинарные кавычки
В строковых литералах, где мы хотим подавить интерполяцию и специальную обработку обратных слешей. Другими словами, ситуации, в которых использование двойных кавычек было бы неуместным.
Без кавычек
В тех случаях, когда мы абсолютно уверены в том, что нет проблем с разделением или смещением слов, или мы хотим разделить и сузить слово .
Примеры
Двойные кавычки
буквенные строки с пробелами ("StackOverflow rocks!" , "Steve's Apple")
переменные расширения ( "$var", "${arr[@]}")
подстановки команд ( "$(ls)", "`ls`")
globs, где путь к каталогу или часть имени файла содержит пробелы ( "/my dir/"*)
В соответствии с этими рекомендациями можно было бы получить список файлов в корневом каталоге, написав "ls" "/" фразу «все строковые контексты», которую необходимо уточнить.
Уильям Перселл
5
В [[ ]], кавычки имеют значение в правой части =/ ==и =~: это делает разницу между интерпретацией строки как шаблона / регулярного выражения или буквально.
Бенджамин В.
6
Хороший обзор, но комментарии @ BenjaminW. Стоит интегрировать, и ANSI C-цитируемые строки ( $'...') обязательно должны иметь свой собственный раздел.
mklement0
3
@ mklement0, действительно, они эквивалентны. Эти руководящие указания указывают на то, что вы должны всегда печатать "ls" "/"вместо более распространенных ls /, и я считаю это основным недостатком руководящих принципов.
Уильям Перселл
4
Для без кавычек вы можете добавить назначение переменной или case:)
PesaThe
4
Я обычно использую кавычки как "$var"для безопасности, если я не уверен, что $varне содержит места.
Я использую $varкак простой способ объединения строк:
lines="`cat multi-lines-text-file.txt`"
echo "$lines"## multiple lines
echo $lines ## all spaces (including newlines) are zapped
Последний комментарий несколько вводит в заблуждение; новые строки эффективно заменяются пробелами, а не просто удаляются.
tripleee
-1
Для использования переменных в сценарии оболочки используйте "" переменные в кавычках, поскольку переменная в кавычках означает, что переменная может содержать пробелы или специальные символы, которые не влияют на выполнение сценария оболочки. Иначе, если вы уверены, что в имени переменной нет пробелов или специальных символов, вы можете использовать их без "".
Пример:
echo "$ url name" - (Может использоваться всегда)
echo "$ url name" - (не может использоваться в таких ситуациях, поэтому примите меры предосторожности перед его использованием)
Ответы:
Общее правило: заключите его в кавычки, если оно может быть пустым или содержать пробелы (или любые пробельные символы) или специальные символы (подстановочные знаки). Не цитирование строк с пробелами часто приводит к тому, что оболочка разбивает один аргумент на множество.
$?
кавычки не нужны, так как это числовое значение. Если$URL
необходимо , это зависит от того, что вы позволяете там и по- прежнему хотите ли вы аргумент , если он пуст.Я склонен всегда цитировать строки просто по привычке, потому что так безопаснее.
источник
IFS=0
, тоecho $?
может быть очень удивительно.cp $source1 $source2 $dest
, но если по какой - то непредвиденной причинеdest
не делает приготовьтесь, третий аргумент просто исчезает, и он будет молча копироватьsource1
черезsource2
вместо давая вам соответствующая ошибка для пустого места назначения (как если бы вы указали каждый аргумент).quote it if...
мыслительный процесс задом наперед - кавычки - это не то, что вы добавляете, когда нужно, а то, что вы удаляете, когда это необходимо. Всегда заключайте строки и сценарии в одинарные кавычки, если только вам не нужно использовать двойные кавычки (например, чтобы разрешить расширение переменной) или вам не нужно использовать кавычки (например, чтобы выполнять глобализацию и расширение имени файла).Вкратце, процитируйте все, где вам не требуется оболочка для разделения токенов и подстановочных знаков.
Одинарные кавычки защищают текст между ними дословно. Это подходящий инструмент, когда вам нужно убедиться, что оболочка вообще не касается строки. Как правило, это предпочтительный механизм цитирования, когда вам не требуется переменная интерполяция.
Двойные кавычки подходят, когда требуется переменная интерполяция. С подходящими адаптациями это также хороший обходной путь, когда вам нужны одинарные кавычки в строке. (Не существует простого способа избежать одиночной кавычки между одинарными кавычками, потому что в одинарных кавычках нет механизма перехода - если бы он был, они бы не цитировали полностью дословно.)
Никакие кавычки не подходят, когда вам конкретно требуется, чтобы оболочка выполняла разбиение токена и / или расширение по шаблону.
Расщепление токенов;
В отличие от:
(Цикл выполняется только один раз над строкой в кавычках.)
(Цикл выполняется только один раз, над литеральной строкой в одинарных кавычках.)
Расширение подстановочного знака:
В отличие от:
(Там нет файла с именем буквально
file*.txt
.)(Нет файла с именем
$pattern
тоже нет!)В более конкретных терминах все, что содержит имя файла, обычно должно заключаться в кавычки (поскольку имена файлов могут содержать пробелы и другие метасимволы оболочки). Все, что содержит URL, обычно следует заключать в кавычки (поскольку многие URL содержат метасимволы оболочки, такие как
?
и&
). Все, что содержит регулярное выражение, обычно должно быть заключено в кавычки (то же самое). Все, что содержит значительные пробелы, кроме одинарных пробелов между непробельными символами, должно быть заключено в кавычки (потому что в противном случае оболочка перебирает пробельные символы в эффективные одиночные пробелы и обрезает любые начальные или конечные пробельные символы).Когда вы знаете, что переменная может содержать только значение, которое не содержит метасимволов оболочки, заключение в кавычки необязательно. Таким образом, без кавычек
$?
в основном нормально, потому что эта переменная может содержать только одно число. Тем не мение,"$?"
это также правильно, и рекомендуется для общей последовательности и правильности (хотя это моя личная рекомендация, а не общепризнанная политика).Значения, которые не являются переменными, в основном следуют тем же правилам, хотя вы можете также избегать любых метасимволов вместо того, чтобы заключать их в кавычки. В типичном примере URL-адрес, содержащий
&
в нем, будет обрабатываться оболочкой как фоновая команда, если метасимвол не экранирован или не заключен в кавычки:(Конечно, это также происходит, если URL-адрес находится в переменной без кавычек.) Для статической строки наиболее целесообразно использовать одинарные кавычки, хотя любая форма цитирования или экранирования здесь работает.
Последний пример также предлагает другую полезную концепцию, которую я люблю называть «цитатами на качелях». Если вам нужно смешать одинарные и двойные кавычки, вы можете использовать их рядом друг с другом. Например, следующие строки в кавычках
могут быть вставлены вместе, образуя одну длинную строку после токенизации и удаления кавычек.
Это не очень разборчиво, но это обычная техника и поэтому полезно знать.
Кроме того, сценарии обычно не должны использоваться
ls
ни для чего. Чтобы расширить подстановочный знак, просто ... используйте его.(Цикл совершенно лишний в последнем примере;
printf
особенно хорошо работает с несколькими аргументами.stat
Также. Но зацикливание на совпадении с подстановочными знаками является обычной проблемой, и часто выполняется неправильно.)Переменная, содержащая список токенов для зацикливания или подстановочный знак для расширения, встречается реже, поэтому мы иногда сокращаем, чтобы «заключить в кавычки все, если вы точно не знаете, что делаете».
источник
Вот трехточечная формула для цитат в целом:
Двойные кавычки
В тех случаях, когда мы хотим подавить разбиение и сглаживание слов. Также в тех случаях, когда мы хотим, чтобы литерал обрабатывался как строка, а не как регулярное выражение.
Одинарные кавычки
В строковых литералах, где мы хотим подавить интерполяцию и специальную обработку обратных слешей. Другими словами, ситуации, в которых использование двойных кавычек было бы неуместным.
Без кавычек
В тех случаях, когда мы абсолютно уверены в том, что нет проблем с разделением или смещением слов, или мы хотим разделить и сузить слово .
Примеры
Двойные кавычки
"StackOverflow rocks!"
,"Steve's Apple"
)"$var"
,"${arr[@]}"
)"$(ls)"
,"`ls`"
)"/my dir/"*
)"single'quote'delimited'string"
)"${filename##*/}"
)Одинарные кавычки
'Really costs $$!'
,'just a backslash followed by a t: \t'
)'The "crux"'
)$'\n\t'
)$'{"table": "users", "where": "first_name"=\'Steve\'}'
)Без кавычек
$$
,$?
,$#
т. д.)((count++))
,"${arr[idx]}"
,"${string:start:length}"
[[ ]]
выражение, свободное от проблем с разделением слов и глобализацией (это вопрос стиля и мнения могут сильно различаться)for word in $words
)for txtfile in *.txt; do ...
)~
быть интерпретированы как$HOME
(~/"some dir"
но не"~/some dir"
)Смотрите также:
источник
"ls" "/"
фразу «все строковые контексты», которую необходимо уточнить.[[ ]]
, кавычки имеют значение в правой части=
/==
и=~
: это делает разницу между интерпретацией строки как шаблона / регулярного выражения или буквально.$'...'
) обязательно должны иметь свой собственный раздел."ls" "/"
вместо более распространенныхls /
, и я считаю это основным недостатком руководящих принципов.case
:)Я обычно использую кавычки как
"$var"
для безопасности, если я не уверен, что$var
не содержит места.Я использую
$var
как простой способ объединения строк:источник
Для использования переменных в сценарии оболочки используйте "" переменные в кавычках, поскольку переменная в кавычках означает, что переменная может содержать пробелы или специальные символы, которые не влияют на выполнение сценария оболочки. Иначе, если вы уверены, что в имени переменной нет пробелов или специальных символов, вы можете использовать их без "".
Пример:
echo "$ url name" - (Может использоваться всегда)
echo "$ url name" - (не может использоваться в таких ситуациях, поэтому примите меры предосторожности перед его использованием)
источник