Может кто-нибудь сказать мне, должен ли я заключать в кавычки переменные в сценарии оболочки?
Например, верно ли следующее:
xdg-open $URL
[ $? -eq 2 ]
или
xdg-open "$URL"
[ "$?" -eq "2" ]
И если так, то почему?
Может кто-нибудь сказать мне, должен ли я заключать в кавычки переменные в сценарии оболочки?
Например, верно ли следующее:
xdg-open $URL
[ $? -eq 2 ]
или
xdg-open "$URL"
[ "$?" -eq "2" ]
И если так, то почему?
Ответы:
Общее правило: заключите его в кавычки, если оно может быть пустым или содержать пробелы (или любые пробельные символы) или специальные символы (подстановочные знаки). Не цитирование строк с пробелами часто приводит к тому, что оболочка разбивает один аргумент на множество.
$?
кавычки не нужны, так как это числовое значение. Если $URL
необходимо , это зависит от того, что вы позволяете там и по- прежнему хотите ли вы аргумент , если он пуст.
Я склонен всегда цитировать строки просто по привычке, потому что так безопаснее.
IFS=0
, то echo $?
может быть очень удивительно.
cp $source1 $source2 $dest
, но если по какой - то непредвиденной причине dest
не делает приготовьтесь, третий аргумент просто исчезает, и он будет молча копировать source1
через source2
вместо давая вам соответствующая ошибка для пустого места назначения (как если бы вы указали каждый аргумент).
quote it if...
мыслительный процесс задом наперед - кавычки - это не то, что вы добавляете, когда нужно, а то, что вы удаляете, когда это необходимо. Всегда заключайте строки и сценарии в одинарные кавычки, если только вам не нужно использовать двойные кавычки (например, чтобы разрешить расширение переменной) или вам не нужно использовать кавычки (например, чтобы выполнять глобализацию и расширение имени файла).
Вкратце, процитируйте все, где вам не требуется оболочка для разделения токенов и подстановочных знаков.
Одинарные кавычки защищают текст между ними дословно. Это подходящий инструмент, когда вам нужно убедиться, что оболочка вообще не касается строки. Как правило, это предпочтительный механизм цитирования, когда вам не требуется переменная интерполяция.
$ 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.
Это не очень разборчиво, но это обычная техника и поэтому полезно знать.
Кроме того, сценарии обычно не должны использоваться ls
ни для чего. Чтобы расширить подстановочный знак, просто ... используйте его.
$ 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
Также. Но зацикливание на совпадении с подстановочными знаками является обычной проблемой, и часто выполняется неправильно.)
Переменная, содержащая список токенов для зацикливания или подстановочный знак для расширения, встречается реже, поэтому мы иногда сокращаем, чтобы «заключить в кавычки все, если вы точно не знаете, что делаете».
Вот трехточечная формула для цитат в целом:
Двойные кавычки
В тех случаях, когда мы хотим подавить разбиение и сглаживание слов. Также в тех случаях, когда мы хотим, чтобы литерал обрабатывался как строка, а не как регулярное выражение.
Одинарные кавычки
В строковых литералах, где мы хотим подавить интерполяцию и специальную обработку обратных слешей. Другими словами, ситуации, в которых использование двойных кавычек было бы неуместным.
Без кавычек
В тех случаях, когда мы абсолютно уверены в том, что нет проблем с разделением или смещением слов, или мы хотим разделить и сузить слово .
Примеры
Двойные кавычки
"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
как простой способ объединения строк:
lines="`cat multi-lines-text-file.txt`"
echo "$lines" ## multiple lines
echo $lines ## all spaces (including newlines) are zapped
Для использования переменных в сценарии оболочки используйте "" переменные в кавычках, поскольку переменная в кавычках означает, что переменная может содержать пробелы или специальные символы, которые не влияют на выполнение сценария оболочки. Иначе, если вы уверены, что в имени переменной нет пробелов или специальных символов, вы можете использовать их без "".
Пример:
echo "$ url name" - (Может использоваться всегда)
echo "$ url name" - (не может использоваться в таких ситуациях, поэтому примите меры предосторожности перед его использованием)