Короче говоря, укажите все, где вы не требуете оболочки для выполнения разделения токенов и расширения подстановочных знаков.
Одиночные кавычки защищают текст между ними дословно. Это правильный инструмент, когда вам нужно убедиться, что оболочка вообще не касается строки. Как правило, это механизм цитирования, когда вам не нужна переменная интерполяция.
$ 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 в unquoted variable.) Для статической строки одинарные кавычки имеют наибольший смысл, хотя здесь используется любая форма цитирования или экранирования.
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.
Это не ужасно читаемо, но это обычная техника и, следовательно, ее хорошо знать.
В стороне, скрипты should usually not use ls
for anything. Чтобы развернуть подстановочный знак, просто ... используйте его.
$ 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"
> done
Found file: file1.txt
Found file: file_other.txt
(петля полностью лишняя в последнем примере,. printf
специально прекрасно работает с несколькими аргументами stat
тоже Но зацикливание за матч группового символа является общей проблемой, и часто это делается неправильно.).
Изменена переменная, содержащая список токенов для циклического перехода или подстановочный знак для расширения, поэтому мы иногда сокращаем «процитировать все, если вы точно не знаете, что делаете».
Там нет глупых вопросов. Ну, там _are, _ но это не один из них :-) – paxdiablo
См. Также http://unix.stackexchange.com/questions/171346/security-implications-of-forgetting-to-quote-a-variable- in-bash-posix-shells – tripleee
Этот вопрос получает много дубликатов, многие из которых не связаны с переменными, поэтому я переименовал «значение» вместо «переменной». Надеюсь, это поможет большему количеству людей найти эту тему. – tripleee