Как мне научиться правильно цитировать в bash? - PullRequest
3 голосов
/ 03 апреля 2012

Меня постоянно смущают правила цитирования и оценки при написании сценариев bash. Я знаю некоторые основы, такие как разница между '' и '' и ``, но я все еще слишком часто ошибаюсь и вынужден экспериментировать с попытками разных способов сказать одно и то же.

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

У меня нет проблем с системой LISP для цитат, eval, read, print, syntax-quote. На самом деле я написал небольшое ката, чтобы помочь людям понять, что происходит: http://www.learningclojure.com/2010/11/syntax-quote-kata-for-confused.html

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

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

Ответы [ 3 ]

9 голосов
/ 03 апреля 2012

Учебное пособие Брюса Барнетта по UNIX Shell по цитате потрясающе, а Bash FAQ / подводные камни / разбиение слов статьи имеют массу полезного чаевые. Краткое резюме:

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

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

Обратные пометки предназначены для команд. Они должны использоваться только в том случае, если ваша оболочка не поддерживает $(). Пример: * +1022 *

current_dir=`pwd` # BAD! Don't do this!

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

current_dir="$(pwd)" # OK, but loses newlines at EOF

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

# Works for some commands, but not pwd
current_dirx="$(pwd; echo x)"
current_dir="${current_dirx%x}"
printf %s "$current_dir"

, но есть дополнительная трудность, потому что некоторые команды (например, pwd) добавят символ новой строки в конце своего вывода в любом случае , поэтому вам, возможно, придется удалить это:

# Works for some commands, including pwd
current_dirx="$(pwd; echo x)"
current_dir="${current_dirx%$'\nx'}"
printf %s "$current_dir"

Двойные кавычки могут содержать любой символ (Попробуйте echo -ne "\0" | wc -c), но обратите внимание, что переменные не могут содержать символ NUL.

Цитаты ANSI-C могут содержать любые символы , кроме NUL (Попробуйте echo -ne $'\0' | wc -c), и предоставляют удобные коды перехода, облегчающие работу с ними. специальные символы:

printf %s $'--$`!*@\a\b\E\f\r\t\v\\\'"\360\240\202\211 \n'
printf %q $'--$`!*@\a\b\E\f\r\t\v\\\'"\360\240\202\211 \n'
touch -- $'--$`!*@\a\b\E\f\r\t\v\\\'"\360\240\202\211 \n'
rm -- $'--$`!*@\a\b\E\f\r\t\v\\\'"\360\240\202\211 \n'
1 голос
/ 03 апреля 2012

Используйте одинарные кавычки '' для цитирования необработанного текста (даже обратные косые черты не исключают ничего в одинарных кавычках):

> echo '\'
\
> echo '$PATH'
$PATH

Используйте двойные кавычки "" для цитирования текста, который содержит вещи, которые оболочка должна оценивать, такие как переменные ($bla), вызовы подоболочки ($(ls)) и оценки ($((5 + 3))).

> echo "$PATH"
/home/alfe/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
> echo "$(ls | tail -1)"
bla
> echo "$((5 + 3))"
8

Используйте обратные пометки ``, если по какой-то причине вы не можете использовать $() (например, в редких случаях, когда вам нужно sh вместо bash. Обычно используют $() для сбора выходных данных подоболочки в текущую команду.

> echo "$(ls | tail -1) is the last file in the current dir."
bla is the last file in the current dir.

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

> a="four    spaces"
> echo $a
four spaces
> echo "$a"
four    spaces
0 голосов
/ 12 апреля 2012

В командной строке

set -x
set -v

и создайте следующую программу на python 'args.py'

#!/usr/bin/env python

import sys
print sys.argv
for arg in sys.argv[1:]:
    for c in arg:
        print c,"|",
    print

Затем поэкспериментируйте с такими вызовами команд:

U=hello\ world ; V="-->$U<--"; W="1 $U 2 $V 3"; args.py $W

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

...