Почему сравнения сценариев оболочки часто используют x$VAR = xyes?
Я часто вижу это в сценариях сборки проектов, которые используют autotools (autoconf, automake). Когда кто-то хочет проверить значение переменной оболочки, они часто используют эту идиому:
if test "x$SHELL_VAR" = "xyes"; then
...
в чем преимущество этого над просто проверкой значения, как это:
if test $SHELL_VAR = "yes"; then
...
7 ответов
если вы используете оболочку, что делает простой замена и SHELL_VAR
переменная не существует (или пуста), тогда вам нужно следить за крайними случаями. Будут сделаны следующие переводы:
if test $SHELL_VAR = yes; then --> if test = yes; then
if test x$SHELL_VAR = xyes; then --> if test x = xyes; then
первый из них будет генерировать ошибку, так как первый аргумент test
пропал. У второго такой проблемы нет.
ваш случай переводится следующим образом:
if test "x$SHELL_VAR" = "xyes"; then --> if test "x" = "xyes"; then
это может кажется немного избыточно, так как он имеет как кавычки, так и "x", но он также будет обрабатывать переменную с пробелами в ней, не давая этого как два аргументы .
другая причина (кроме пустых переменных) связана с обработкой опций. Если вы пишете:
if test "" = "abc" ; then ...
и имеет значение
-n
или -z
или любые другие допустимые параметры для test
command, синтаксис неоднозначен. The x
at фронт предотвращает ведущую черточку от быть выбранным как вариант к test
.
имейте в виду, что это зависит от оболочки. Некоторые раковины (csh
для одного, я думаю) будет горько жаловаться, если переменная окружения не существует, а не просто возвращает пустую строку).
другая причина, которую никто еще не упомянул, связана с обработкой опций. Если вы пишете:
if [ "" = "abc" ]; then ...
и $1 имеет значение '- n', синтаксис тестовой команды неоднозначен; неясно, что вы тестировали. "X" на фронте предотвращает ведущую черточку от причинять тревогу.
вы должны смотреть на действительно древние оболочки, чтобы найти тот, где тестовая команда не имеет поддержки -n
или -z
; версия 7 (1978)test
командование включало их. Это не совсем неуместно - некоторые вещи UNIX версии 6 сбежали в BSD, но в эти дни вам будет очень сложно найти что-то древнее в текущем использовании.
не использовать двойные кавычки вокруг значений опасно, как указал ряд других людей. Действительно, если есть шанс, что имена файлов могут содержать пробелы (MacOS X и Windows в некоторой степени поощряют это, и Unix всегда поддерживал его, Хотя такие инструменты, как xargs
сделать это harder), то вы должны заключать имена файлов в двойные кавычки каждый раз, когда вы их используете. Если вы не отвечаете за значение (например, во время обработки опций, и вы устанавливаете переменную в " НЕТ "при запуске и "да", когда флаг включен в командную строку), то небезопасно использовать некотируемые формы переменных, пока вы не доказали их безопасность, и вы можете делать это все время для многих целей. Или документ, что ваши скрипты будут терпеть неудачу, если пользователи попытаются обработать файлы с помощью пробелы в именах. (И есть другие персонажи, о которых тоже нужно беспокоиться-например, backticks может быть довольно неприятным.)
есть две причины, которые я знаю для этого соглашения:
http://tldp.org/LDP/abs/html/comparison-ops.html
в составном тесте даже цитирования строковой переменной может быть недостаточно. [- n "$string "- o "$a " = "$b"] может вызвать ошибку с некоторыми версиями Bash, если $string пустая. Безопасный способ-добавить дополнительный символ к возможно, пустые переменные, ["x$string"!= x-o "x$a" = "x$b"] (отмена " x из.)
во-вторых, в других оболочках, кроме Bash, особенно более старых, условия тестирования, такие как'- z ' для проверки пустой переменной, не существовали, поэтому, пока это:
if [ -z "$SOME_VAR" ]; then
echo "this variable is not defined"
fi
будет отлично работать в BASH, если вы стремитесь к переносимости в различных средах UNIX, где вы не можете быть уверены, что оболочка по умолчанию будет Bash и поддерживает ли она условие теста-z, безопаснее использовать форму, если ["x$SOME_VAR" = "x"], так как это всегда будет иметь предполагаемый эффект. По сути, это старый трюк сценариев оболочки для поиска пустой переменной, и он по-прежнему используется сегодня для обратной совместимости, несмотря на наличие более чистых методов.
Я рекомендую вместо этого:
if test "yes" = "$SHELL_VAR"; then
так как это не некрасиво x
и все-таки решает проблему, упомянутую на https://stackoverflow.com/a/174288/895245 что $SHELL_VAR
начинается с -
и быть прочитанным как вариант.
Я считаю, что это из-за
SHELLVAR=$(true)
if test $SHELLVAR = "yes" ; then echo "yep" ; fi
# bash: test: =: unary operator expected
а также
if test $UNDEFINEDED = "yes" ; then echo "yep" ; fi
# bash: test: =: unary operator expected
и
SHELLVAR=" hello"
if test $SHELLVAR = "hello" ; then echo "yep" ; fi
# yep
однако это обычно должно работать
SHELLVAR=" hello"
if test "$SHELLVAR" = "hello" ; then echo "yep" ; fi
#<no output>
но когда он жалуется на выходе где-то еще, его трудно сказать, что его жалуется, Я думаю, так
SHELLVAR=" hello"
if test "x$SHELLVAR" = "xhello" ; then echo "yep" ; fi
работает так же хорошо, но было бы легче для отладки.
Если вы не делаете "x$SHELL_VAR", то если $SHELL_VAR не определен, вы получаете ошибку о том, что "=" не является монадическим оператором или что-то в этом роде.