Почему `if $(true) ; then ... fi` успешна?

Навеяно этим вопросом:

Что должен делать оператор if, когда условие является подстановкой команды, при которой команда не производит никакого вывода?

ПРИМЕЧАНИЕ: Пример - if $(true); then ... , а не if true ; then ...

Например, учитывая:

if $(true) ; then echo yes ; else echo no ; fi

Я бы подумал, что $(true) должен быть заменен выводом команды true, то есть ничем. Тогда это должно быть эквивалентно либо этому:

if "" ; then echo yes ; else echo no ; fi

которое выводит no, потому что не существует команды, имя которой является пустой строкой, либо этому:

if ; then echo yes ; else echo no ; fi

что является синтаксической ошибкой.

Но эксперимент показывает, что если команда не выводит никаких данных, то оператор if воспринимает это как true или false в зависимости от статуса команды, а не от ее вывода.

Вот сценарий, демонстрирующий такое поведение:

#!/bin/bash

echo -n 'true:          ' ; if true          ; then echo yes ; else echo no ; fi
echo -n 'false:         ' ; if false         ; then echo yes ; else echo no ; fi
echo -n '$(echo true):  ' ; if $(echo true)  ; then echo yes ; else echo no ; fi
echo -n '$(echo false): ' ; if $(echo false) ; then echo yes ; else echo no ; fi
echo -n '$(true):       ' ; if $(true)       ; then echo yes ; else echo no ; fi
echo -n '$(false):      ' ; if $(false)      ; then echo yes ; else echo no ; fi
echo -n '"":            ' ; if ""            ; then echo yes ; else echo no ; fi
echo -n '(nothing):     ' ; if               ; then echo yes ; else echo no ; fi

и вот вывод, который я получаю (Ubuntu 11.04, bash 4.2.8):

true:          yes
false:         no
$(echo true):  yes
$(echo false): no
$(true):       yes
$(false):      no
"":            ./foo.bash: line 9: : command not found
no
./foo.bash: line 10: syntax error near unexpected token `;'
./foo.bash: line 10: `echo -n '(nothing):     ' ; if               ; then echo yes ; else echo no ; fi'

Первые четыре строки ведут себя так, как я ожидал; строки $(true) и $(false) удивляют.

Дальнейший эксперимент (здесь не показан) показывает, что если команда между $( и ) производит вывод, то ее статус выхода не влияет на поведение if.

Я вижу похожее поведение (но разные сообщения об ошибках в некоторых случаях) с bash, ksh, zsh, ash и dash.

Я не вижу ничего в документации по bash или в спецификации POSIX "Shell Command Language", чтобы объяснить это.

(Или, возможно, я упускаю что-то очевидное.)

EDIT : В свете принятого ответа, вот еще один пример такого поведения:

command='' ; if $command ; then echo yes ; else echo no ; fi

или, эквивалентно:

command=   ; if $command ; then echo yes ; else echo no ; fi

22
задан Community 23 May 2017 в 10:29
поделиться