О неоправданно хорошей работе [ -z $var ]

в 13:58, , рубрики: linux, ruvds_переводы, Блог компании RUVDS.com, системное администрирование

Есть такой сабреддит — /r/nononoyes, где публикуют видео, в которых происходит что-то такое, что, на первый взгляд, кажется ужасно неправильным, идущим к катастрофе. Но в конце всё, чудесным образом, заканчивается хорошо.

В том сабреддите хорошо смотрелась бы команда [ -z $var ].

О неоправданно хорошей работе [ -z $var ] - 1

Это — конструкция, которая используется в bash для проверки того, является ли переменная пустой. Но тут не хватает кавычек (её более правильный вариант выглядел бы как [ -z "$var" ]). Это, при работе с переменными, которые могут быть пустыми, часто приводит к неприятностям.

Рассмотрим обратное выражение — [ -n $var ], которое проверяет переменную на то, что она является непустой. Та же проблема с кавычками делает её полностью бесполезной:

Входные данные Ожидаемый результат [ -n $var ]
""
False
True!
"foo"
True
True
"foo bar"
True
False!

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

Нахождение результатов работы команды [ зависит от количества аргументов. Значения аргументов гораздо слабее влияют на результат. Вот упрощённая выдержка из описания POSIX-команды test, составляя которую, я не обращал внимания на отрицание:

Количество аргументов Действие Типичный пример
0 Возврат False.
[ ]
1 Возврат True, если аргумент $1 не является пустым.
[ "$var" ]
2 Применение унарного оператора $1 к $2.
[ -x "/bin/ls" ]
3 Применение бинарного оператора $2 к $1 и к $3.
[ 1 -lt 2 ]

Если это учесть — становится понятным то, почему команда [ -n $var ] в двух случаях ведёт себя неправильно:

  • Когда переменная является пустой и при этом не заключена в кавычки, она удаляется, и мы передаём команде 1 аргумент — литеральную строку -n. Так как -n не является пустой строкой — команда выдаёт True, а должна была бы выдать False.
  • Когда переменная содержит foo bar и не заключена в кавычки, она разделяется на два аргумента, в результате мы передаём команде 3 аргумента: -n, foo и bar. Так как foo — это не бинарный оператор, результатом работы команды является False (с выдачей сообщения об ошибке), а, на самом деле, результатом должно быть True.

А теперь посмотрим на то, как работает [ -z $var ]:

Входные данные Ожидаемый результат [ -z $var ] Команда test
""
True: пустая переменная
True
1 аргумент: проверка того, является ли -z непустой переменной
"foo"
False: непустая переменная
False
2 аргумента: применение -z к foo
"foo bar"
False: непустая переменная False (ошибка) 3 аргумента: применение foo к -z и bar

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

Другими словами, [ -z $var ] работает гораздо лучше, чем этого можно ожидать.

Конечно, это не значит, что я призываю всех отказаться от кавычек. Для "foo bar" [ -z $var ] вернёт правильный код выхода, но при этом выведет некрасивое сообщение об ошибке. Для ” ” (это — строка, в которой имеются только пробелы) вернёт True, хотя должна вернуть False, так как соответствующий аргумент удаляется так, как если бы он был пустым. Bash, кроме того, что неправильно, при попытке воспользоваться механизмом внедрения кода, пропустит конструкцию var="foo -o x", так как она будет нормально воспринята командой test.

Какова мораль сей басни? Она такая же, как и всегда: не забывайте о кавычках. Даже тогда, когда кажется, что и без них всё работает как надо.

Утилита ShellCheck знает об этих особенностях. Тут можно проверить код, о котором мы говорили. А именно, анализируя конструкцию [ -n $var ], программа разразится гневным сообщением красного цвета, а рассматривая конструкцию [ -z $var ] — всего лишь покажет обычное зелёное предупреждение об отсутствии кавычек.

Сталкивались ли, при работе в bash, с проблемами, связанными с кавычками?

О неоправданно хорошей работе [ -z $var ] - 2
О неоправданно хорошей работе [ -z $var ] - 3

Автор: ru_vds

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js