Я хочу, чтобы мои сценарии оболочки не работали всякий раз, когда выполняемая с ними команда не выполняется
Обычно я делаю это с:
set -e
set -o pipefail
(как правило, я добавляю set -u
также)
Дело в том, что ничего из вышеперечисленного не работает с заменой процесса. Этот код выводит «ok» и завершается с кодом возврата = 0, в то время как я хотел бы, чтобы он потерпел неудачу:
#!/bin/bash -e
set -o pipefail
cat <(false) <(echo ok)
Есть ли что-то эквивалентное "pipefail", кроме как для замены процесса? Любой другой способ передать команде вывод команд, как будто они были файлами, но выдавать ошибку всякий раз, когда любая из этих программ дает сбой?
Решение плохого человека было бы определить, пишут ли эти команды в stderr (но некоторые команды пишут в stderr в успешных сценариях).
Другим решением, более совместимым с posix, было бы использование именованных каналов, но мне нужно использовать эти команды, которые используют подстановку процессов, так как oneliners создаются на лету из скомпилированного кода, а создание именованных каналов усложнит ситуацию (дополнительные команды, ошибка перехвата для удаляя их и т. д.)
источник
mkfifo pipe; { rm pipe; cat <file; } >pipe
. Эта команда будет зависать до тех пор, пока не откроется читатель,pipe
потому что это оболочка, которая выполняет операцию,open()
и так, как только вpipe
ссылке fs есть читатель дляpipe
isrm
'd, а затемcat
копирует infile в дескриптор оболочки для этого канала. И вообще, если вы хотите распространить ошибку из подпрограммы процесса, то сделайте: <( ! : || kill -2 "$$")
$$
замена не работает для меня, так как эта подстановка команд не выполняется, так как команда, использующая подстановку процессов, выполняется внутри конвейера команд, порожденного из кода «не оболочки» (python). Вероятно, я должен создать подпроцесс в Python и программно передать их.kill -2 0
.Ответы:
Вы можете обойти эту проблему, например:
Подоболочка сценария
SIGTERM
d перед выполнением второй команды (other_command
). Командаecho ok
выполняется «иногда»: проблема в том, что подстановки процессов асинхронны. Там нет никакой гарантии , чтоkill $$
команда выполняется до того или после того, как вecho ok
команде. Это вопрос планирования операционных систем.Рассмотрим скрипт bash, подобный этому:
Вывод этого скрипта может быть:
Или:
Вы можете попробовать это, и после нескольких попыток вы увидите два разных порядка в выводе. В первом сценарий был прерван до того, как две другие
echo
команды смогли записать в дескриптор файла. Во втором командаfalse
илиkill
команда, вероятно, были запланированы послеecho
команд.Или более точно: Системный вызов
signal()
от Предприятия обслуживанияkill
населения , который посылает наSIGTERM
сигнал процесс раковин был запланирован (или был доставлен) позже или раньше , чем эхоwrite()
системных вызовов.Но, тем не менее, скрипт останавливается и код выхода не равен 0. Поэтому он должен решить вашу проблему.
Другое решение , конечно, использовать именованные каналы для этого. Но от вашего сценария зависит, насколько сложно было бы реализовать именованные каналы или обходной путь, описанный выше.
Ссылки:
источник
Для справки, и даже если ответы и комментарии были хорошими и полезными, я прекратил реализовывать что-то немного другое (у меня были некоторые ограничения на получение сигналов в родительском процессе, которые я не упомянул в вопросе)
По сути, я закончил делать что-то вроде этого:
Затем я проверяю файл ошибок. Если он существует, я знаю, какая подкоманда завершилась неудачно (и содержимое файла error_file может быть полезным). Более многословный и хакерский, который я изначально хотел, но менее громоздкий, чем создание именованных каналов в однострочном комманде bash.
источник
Этот пример показывает, как использовать
kill
вместе сtrap
.Но
kill
нельзя передать код возврата из вашего подпроцесса в родительский процесс.источник
Аналогично тому, как вы реализуете
$PIPESTATUS
/$pipestatus
с помощью оболочки POSIX, которая ее не поддерживает , вы можете получить статус завершения команд, передав их через канал:Который дает:
Или вы можете использовать
pipefail
и реализовывать процесс подстановки вручную, как если бы вы использовали оболочки, которые его не поддерживают:источник