Вопрос по linux, unix, shell, bash – Когда обернуть кавычки вокруг переменной оболочки?

113

Может кто-нибудь сказать мне, должен ли я заключать в кавычки переменные в сценарии оболочки?

Например, верно ли следующее:

xdg-open $URL 
[ $? -eq 2 ]

или же

xdg-open "$URL"
[ "$?" -eq "2" ]

И если так, то почему?

Там нет глупых вопросов. Ну тамare, но это не один из них :-) paxdiablo
@codeforester Что случилось с отмененным редактированием? tripleee
Связанные с:Difference between single and double quotes in Bash также. codeforester
Этот вопрос содержит много дубликатов, многие из которых не связаны с переменными, поэтому я переименовал в «значение» вместо "переменная". Я надеюсь, что это поможет большему количеству людей найти эту тему. tripleee
Смотрите такжеunix.stackexchange.com/questions/171346/… tripleee

Ваш Ответ

5   ответов
61

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

Одинарные кавычки защищают текст между ними дословно. Это подходящий инструмент, когда вам нужно убедиться, что оболочка вообще не касается строки. Как правило, это предпочтительный механизм цитирования, когда вам не требуется переменная интерполяция.

$ 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 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 тоже. Но зацикливание совпадений с подстановочными знаками является распространенной проблемой и часто выполняется неправильно.)

Переменная, содержащая список токенов для зацикливания или подстановочный знак для расширения, встречается реже, поэтому мы иногда сокращаемся, чтобы «заключить в кавычки все, если вы точно не знаете, что делаете».

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededrelated questionError: User Rate Limit Exceeded
Error: User Rate Limit Exceededmywiki.wooledge.org/BashPitfallsError: User Rate Limit Exceeded
-1

& Quot; Переменные в кавычках как в кавычках означают, что переменная может содержать пробелы или специальные символы, которые не повлияют на выполнение вашего сценария оболочки. Иначе, если вы уверены, что в имени переменной нет пробелов или специальных символов, вы можете использовать их без & quot; & Quot ;.

Пример:

echo & quot; $ url name & quot; - (Может использоваться в любое время)

echo & quot; $ url name & quot; - (Не может использоваться в таких ситуациях, поэтому примите меры предосторожности перед его использованием)

79

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

$? кавычки не нужны, так как это числовое значение. Будь то$URL Это зависит от того, что вы там разрешаете, и хотите ли вы по-прежнему аргумент, если он пуст.

Я склонен всегда цитировать строки просто по привычке, так как это безопаснее.

Error: User Rate Limit ExceededIFS=0Error: User Rate Limit Exceededecho $?Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
14

Double quotes

В тех случаях, когда мы хотим подавить расщепление и смещение слов. Также в тех случаях, когда мы хотим, чтобы литерал обрабатывался как строка, а не как регулярное выражение.

Single quotes

В строковых литералах, где мы хотим подавить интерполяцию и специальную обработку обратных слешей. Другими словами, ситуации, в которых использование двойных кавычек было бы неуместным.

No quotes

В тех случаях, когда мы абсолютно уверены, что у нас нет проблем с разделением слов или глобализацией, или мыdo want word splitting and globbing.

Examples

Double quotes

literal strings with whitespace ("StackOverflow rocks!", "Steve's Apple") variable expansions ("$var", "${arr[@]}") command substitutions ("$(ls)", "`ls`") globs where directory path or file name part includes spaces ("/my dir/"*) to protect single quotes ("single'quote'delimited'string") Bash parameter expansion ("${filename##*/}")

Single quotes

command names and arguments that have whitespace in them literal strings that need interpolation to be suppressed ( 'Really costs $$!', 'just a backslash followed by a t: \t') to protect double quotes ('The "crux"') regex literals that need interpolation to be suppressed use shell quoting for literals involving special characters ($'\n\t') use shell quoting where we need to protect several single and double quotes ($'{"table": "users", "where": "first_name"=\'Steve\'}')

No quotes

around standard numeric variables ($$, $?, $# etc.) in arithmetic contexts like ((count++)), "${arr[idx]}", "${string:start:length}" inside [[ ]] expression which is free from word splitting and globbing issues (this is a matter of style and opinions can vary widely) where we want word splitting (for word in $words) where we want globbing (for txtfile in *.txt; do ...) where we want ~ to be interpreted as $HOME (~/"some dir" but not "~/some dir")

Смотрите также:

Difference between single and double quotes in Bash What are the special dollar sign shell variables? Quotes and escaping - Bash Hackers' Wiki When is double quoting necessary?
Error: User Rate Limit Exceeded"ls" "/"Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded"ls" "/"Error: User Rate Limit Exceededls /Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded[[ ]]Error: User Rate Limit Exceeded=/==Error: User Rate Limit Exceeded=~Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededno quotesError: User Rate Limit Exceededcase :)
Error: User Rate Limit Exceeded$'...'Error: User Rate Limit Exceeded
1

"$var" для безопасности, если я не уверен, что$var не содержит места

Я использую$var как простой способ объединения строк:

lines="`cat multi-lines-text-file.txt`"
echo "$lines"                             ## multiple lines
echo $lines                               ## all spaces (including newlines) are zapped
Error: User Rate Limit Exceeded

Похожие вопросы