.png)
Как мне передать команды по конвейеру и внутри скрипта решить, следует ли прерывать конвейер или нет?
Это похоже наэтот вопрос. Но вместо этого awk
я хотел бы использовать свой собственный скрипт:
check_ip | update_bind9
check_ip
необходимо найти внешний IP-адрес ( curl -s ifconfig.co
) и сравнить его с IP-адресом, сохраненным в файле ( ~/.ip
).
Вот главный вопрос:
Если IP изменился, check_ip
то следует передать IP через канал. Если нет, то следует разорвать канал.
Это check_ip
разрывает канал или update_bind9
игнорирует вызов, если он не вызван с IP?
Я провел несколько тестов, назвав: check_ip | echo "ok"
.
Я пытался exit 0
, exit 1
, return true
, return false
. Пытался set -e
. Безуспешно.
решение1
Все компоненты трубопроводаначать одновременно– вторая команда всегда будет запущена, независимо от того, что происходит в первой команде.
Итак, это вторая команда, которая должна обрабатывать пустой stdin.
Но я бы сказал, что трубы изначально не подходят для этих целей.
(Может быть, вы путаете |
(pipe) с ||
(boolean OR)? Последнееявляется(Часто используется как более короткая альтернатива if/then, например, x || y
вызовет y только в случае неудачи x, и, аналогично, x && y
вызовет y только в случае успеха x.)
В общем случае следует использовать блок if/then. Например, if check_ip
сам возвращает 0 (успех), когда адреса разные, но 1 (неудача), когда они одинаковые, это будет выглядеть так:
if addr=$(check_ip); then
echo "$addr" | update_bind9
fi
В качестве альтернативы, если update_bind9 может определить адрес самостоятельно (без чтения stdin), это будет выглядеть так:
if check_ip_needs_updating; then
update_bind9
fi
решение2
Этот другой ответхорошо. Однако, если вам действительно нужно условное прохождение, то вы можете обнаружить,ifne
полезный:
ifne
выполняет следующую команду только в том случае, если стандартный ввод не пуст.
В вашем случае это будет как check_ip | ifne update_bind9
.
Скорее всего, ifne
не установлен в вашем Linux по умолчанию. В моем Debian 10 он есть в moreutils
пакете. Кто-то может подумать, что дополнительный инструмент совершенно излишен, поскольку мы можем сохранить вывод check_ip
в переменной и условно использовать его повторно, как в упомянутом ответе:
if addr=$(check_ip); then echo "$addr" | update_bind9 fi
Условие может быть [ -n "$addr" ]
, что угодно; важно то, что мы используем переменную. Код, подобный приведенному выше, может решить вашу проблему, но в целом с ним связано как минимум три проблемы. Предположим command1 | command2
вместо check_ip | update_bind9
. Решение обобщается до:
if foo=$(command1); then
echo "$foo" | command2
fi
А потом:
foo=$(command1)
удалит все конечные символы новой строки из выводаcommand1
. Затемecho "$foo"
(илиprintf … "$foo"
) добавит ровно один символ новой строки (или некоторое фиксированное их количество соответственно). По этой причинеcommand2
может не получиться точный вывод отcommand1
.command1
может выдавать вывод, содержащий символ(ы) NUL. Bash не может хранить NUL в переменной (большинство оболочек не могут; zsh может). Если появляется NUL, тоcommand2
не будет получать точный вывод изcommand1
.command1
может создать огромный или даже бесконечный поток, поэтому сохранение его в переменной может оказаться невозможным.
Использование файла вместо переменной решает все проблемы, кроме последней. command1 | ifne command2
защищен от всех трех проблем.