Почему печатный ноль обрабатывается иначе, чем буквальный нуль в условии? - PullRequest
2 голосов
/ 16 мая 2019

Обе эти команды, имеющие одинаковый результат, имеют смысл:

$ if 1; then printf "success\n"; else printf "failure\n"; fi
-bash: 1: command not found
failure

$ if $(printf 1); then printf "success\n"; else printf "failure\n"; fi
-bash: 1: command not found
failure

, поскольку $(printf "1") печатает 1 до того, как 1 будет выполнено в if.

Учитывая, что, однако, я не понимаю, почему они дают разные результаты:

$ if ""; then printf "success\n"; else printf "failure\n"; fi
-bash: : command not found
failure

$ if ; then printf "success\n"; else printf "failure\n"; fi
-bash: syntax error near unexpected token `;'

$ if $(printf ""); then printf "success\n"; else printf "failure\n"; fi
success

Почему вывод нулевой строки с помощью $(printf "") будет обрабатываться иначе, чем нулевая строка, явно закодированная как "" в первой команде или отсутствующий аргумент из второй команды? Что именно выполняется в последней команде и, как выясняется, успешно и почему?


Обновление - убедитесь, что я его получу!

Поэтому, применяя ответ @ chepner к приведенным выше сценариям, я добавил пояснения (пожалуйста, исправьте меня, если я что-то не так):

$ if 1; then printf "success\n"; else printf "failure\n"; fi
-bash: 1: command not found
failure

Оболочка анализирует if 1;, видит что-то, что она ожидает от команды, но на самом деле это число 1 и поэтому не может "команда не найдена"

$ if $(printf 1); then printf "success\n"; else printf "failure\n"; fi
-bash: 1: command not found
failure

Оболочка анализирует if $(printf 1);, видит что-то, что она ожидает от команды, $(printf 1), успешно выполняет ее, которая выдает 1. Оболочка видит, что что-то было выведено (1) и выдает любой вывод в этом контексте оболочка ожидает, что «что-то» также будет командой, которую она должна выполнить, но на самом деле это число 1, и поэтому не может «команда не найдена».

$ if ""; then printf "success\n"; else printf "failure\n"; fi
-bash: : command not found
failure

Оболочка анализирует if "";, видит что-то, что она ожидает от команды, но на самом деле это строка "" и поэтому не удается "команда не найдена"

$ if ; then printf "success\n"; else printf "failure\n"; fi
-bash: syntax error near unexpected token `;'

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

$ if $(printf ""); then printf "success\n"; else printf "failure\n"; fi
success

Оболочка анализирует if $(printf "");, видит что-то, что она ожидает от команды, $(printf ""), успешно выполняет ее, и ничего не выводит, что оболочка принимает как таковую, и поэтому не имеет новой команды для выполнения, и поэтому применяет выход из успеха состояние последней команды, которую она выполнила ($(printf "")) для условия в целом и, таким образом, успешно выполняет.

Ответы [ 2 ]

2 голосов
/ 16 мая 2019

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


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

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

Пропуская немного деталей, достаточно сказать, что строка $(print "") анализирует как составной список.Оценка не требуется, поэтому if $(print ""); then ... успешно анализирует.

После завершения анализа теперь оболочка должна оценить .Процесс этого описан в разделе «ПРОСТОЕ РАСШИРЕНИЕ КОМАНДЫ» на справочной странице bash, цитируемой ниже во всей полноте с выделенными соответствующими отрывками:

ПРОСТОЕ РАСШИРЕНИЕ КОМАНДЫ

Когдавыполняется простая команда, оболочка выполняет следующие расширения, назначения и перенаправления слева направо.

  1. Слова, которые синтаксический анализатор пометил как присвоения переменных (предшествующие командеимя) и перенаправления сохраняются для последующей обработки.

  2. Слова, которые не являются переменными назначениями или перенаправлениями, раскрываются. Если после раскрытия остаются слова,первое слово берется в качестве имени команды, а остальные слова являются аргументами.

  3. Перенаправления выполняются, как описано выше в разделе REDIRECTION.

  4. Текст после = в каждом назначении переменной подвергается расширению тильды, расширению параметров, подстановке команд, арифметикеРасширение метики и удаление кавычек перед присвоением переменной.

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

    Если имя команды не найдено, перенаправления выполняются, но не влияюттекущая оболочка среды.Ошибка перенаправления приводит к выходу команды с ненулевым статусом.

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

Итак, $(print "") успешно, но расширяется до пустого списка слов.В результате условие для оператора if «выполняется» путем немедленного возврата со статусом завершения подстановки команды, в результате чего берется истинная ветвь.

1 голос
/ 16 мая 2019

Посмотрите на коды выхода:

$ 1; echo $?
1: command not found
127

$ $(printf 1); echo $?
1: command not found
127

$ ""; echo $?
Command '' not found    
127

$(printf ""); echo $?
0

Вы, вероятно, хотели:

$ if [ 1 ]; then printf "success\n"; else printf "failure\n"; fi
success

$ if [ $(printf 1) ]; then printf "success\n"; else printf "failure\n"; fi
success

$ if [ "" ]; then printf "success\n"; else printf "failure\n"; fi
failure

$ if [ $(printf "") ]; then printf "success\n"; else printf "failure\n"; fi
failure

Обратите внимание на пробел после [ и до ]

Чек man [

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...