Назад | Перейти на главную страницу

Оценка обратных кавычек в bash

Меня смущает оценка обратных кавычек в bash. Я видел подобный код раньше, который имеет смысл:

RESULT=`whoami`

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

if `wget google.com -T 2 -t 1 -o /dev/null`; then 
   echo "Internet ok"
fi

Это проверка подключения к Интернету путем попытки получить домашнюю страницу Google (с -t 1 за одну попытку -T 2 для 2-секундного таймаута и перенаправления на /dev/null поскольку он на самом деле не хочет вывода, а просто хочет увидеть, удастся ли он). Код читается так, как будто автор ожидал, что обратные кавычки будут оценивать код выхода wget команда, а не вывод.

Но это действительно работает. Он печатает Internet ok если он может подключиться к google.com, и если я изменю URL-адрес на какой-то бессмысленный URL-адрес, который не существует, он не удовлетворяет условию if и ничего не печатает. Я не понимаю, почему это работает.

Самостоятельный запуск wget команда с действительными и недопустимыми URL-адресами ничего не выводит в обоих случаях и отличается только кодом выхода.

Я пришел к выводу, что есть специальная конструкция для if с последующими обратными кавычками, которые возвращают код выхода, а не результат. Я ошибся?

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

Более полный обзор можно найти Вот.


РЕДАКТИРОВАТЬ

Обратные кавычки инициируют подстановку команд, которая выполняется в подоболочке и возвращает код выхода. if просто проверяет коды возврата, вывод команды не используется.

Чтобы сравнить вывод команды, вы можете использовать [ , который должен быть закрыт ], что по сути является тестом. Тест может быть любым

  • из man test
  • сравнение строк

    [ "hello" == "test" ]
    
  • целочисленный тест

    [ 2 -eq 3 ]  
    

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

Итак, вы имеете в виду следующее.

if [ "`wget google.com -T 2 -t 1 -o /dev/null`" == "" ]
then 
    echo "emptY"
fi

Но это не имело бы особого смысла из-за перенаправления вывода на /dev/null ты всегда будешь правдой от [ "wget google.com -T 2 -t 1 -o / dev / null" == "" ].
С другой стороны, также было бы бесполезно проверять, есть ли на выходе wget команда действительно содержит вывод, исключая -o /dev/null, потому что даже в случае ошибки вы получите результат, но с разными кодами возврата.

В сценариях оболочки bash if в наши дни избегают обратных кавычек и используют подстановку команд $(...) синтаксис вместо этого.

Он более четкий, чем очень расплывчатые обратные кавычки, и поддерживает вложение, что невозможно в обратных кавычках. I.E:

command $(command two $(command three))

Я наконец получил четкий ответ на этот вопрос через ветка обсуждения в списке рассылки bash. Вывод такой:

  • В этом нет ничего особенного if здесь, он просто выполняет команду после if а затем ветвление на основе кода выхода этой команды. Неожиданное поведение здесь вместо этого приписывается самой подстановке команд.
  • Команда с обратным апострофом (подстановка команд) всегда оценивается как вывод команды внутри них, а не кода выхода (это не новость, а просто подтверждение того, используются ли обратные кавычки в if или нет не имеет значения).
  • Основываясь на двух вышеупомянутых пунктах, неочевидная причина, по которой if `cmd` ... управляет if тело на основе код выхода из cmd когда cmd ничего не пишет в стандартный вывод заключается в том, что существует правило спецификации POSIX о выполнении команд оболочки, которое гласит:

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

ссылка: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html

  • Так что только потому, что в случае cmd ничего не записывает в stdout, оболочка - вместо того, чтобы выполнять пустую команду - берет код выхода подстановки команды (код выхода cmd сам) и возвращает его как код выхода родительской команды, которая затем всплывает до if.

Чтобы лучше проиллюстрировать это, посмотрите следующий пример:

$ `true`
$ echo $?
0
$ `false`
$ echo $?
1

Оболочка сначала запускается true который ничего не передает на стандартный вывод, поэтому результирующая команда пуста. Там, где я ожидал, что пустая команда либо детерминированно завершится успешно, либо не удастся, в соответствии с приведенным выше правилом, она завершается кодом выхода true а не «код выхода пустой команды».