Хадсон: "да: стандартный вывод: сломанная труба"
Мне нужно запустить оболочку script в hudson. Для этого script нужен ответ от пользователя. Чтобы дать автоматический ответ, я выполнил следующую командную строку:
yes | ./MyScript.sh
Это хорошо работает в терминале Ubuntu. Но когда я использую ту же команду в задаче Хадсона, script будет автоматизирован и сделает всю необходимую работу, но в конце я получаю эти две строки ошибки:
yes: standard output: Broken pipe
yes: write error
И это приводит к отказу от моей работы Хадсона.
Как мне изменить свою командную строку, чтобы хорошо работать в Hudson?
Спасибо.
Ответы
Ответ 1
Но как бы вы объяснили, что я не получаю эту ошибку при запуске script локально, но я получаю ошибку при удаленном запуске из работы Хадсона?
Когда вы запускаете его в терминале (локально); yes
убивается сигналом SIGPIPE
, который генерируется, когда он пытается записать в канал, когда MyScript.sh
уже вышел.
Независимо от того, что запускает команду (удаленно) в Hudson ловушки, что сигнал (установите его обработчик на SIG_IGN
, вы можете проверить его, выполнив команду trap
и выполнив поиск SIGPIPE на выходе) и не восстановит сигнал для новых дочерних процессов (yes
и все, что работает MyScript.sh
, например, sh
в вашем случае). Это приводит к ошибке записи (EPIPE
) вместо сигнала. yes
обнаруживает ошибку записи и сообщает об этом.
Вы можете просто проигнорировать сообщение об ошибке:
yes 2>/dev/null | ./MyScript.sh
Вы также можете сообщить об ошибке в отношении компонента, который запускает конвейер. Ошибка заключается в том, что SIGPIPE не восстанавливает обработчик по умолчанию после раздвоения дочернего элемента. Это то, что программы ожидают, когда они запускаются в терминале в системах POSIX. Хотя я не знаю, есть ли стандартный способ сделать это для Java-программы. jvm
, вероятно, вызывает исключение для каждой ошибки записи, поэтому не-умирание на SIGPIPE не является проблемой для Java-программы.
Обычно демонам, таким как hudson, игнорировать сигнал SIGPIPE. Вы не хотите, чтобы ваш демон умирал только потому, что процесс, с которым вы общаетесь с умирающими, и вы все равно будете проверять ошибки записи.
Обычные программы, которые записываются для запуска в терминале, не проверяют статус каждого printf()
для ошибок, но вы хотите, чтобы они умерли, если программы по конвейеру умирают, например, если вы запустите source | sink
конвейер; обычно вы хотите source
завершить процесс как можно скорее, если sink
завершает работу.
EPIPE
ошибка записи возвращается, если сигнал SIGPIPE
отключен (как это выглядит в случае хадсона) или если программа не умирает при его получении (yes
программа не определила никаких обработчиков для SIGPIPE
поэтому он должен умереть при получении сигнала).
Я не хочу игнорировать ошибку, я хочу сделать правильную команду или исправить, чтобы избавиться от этой ошибки.
единственный способ yes
останавливается, если он был убит или столкнулся с ошибкой записи. Если сигнал SIGPIPE
установлен для игнорирования (родителем), и никакой другой сигнал не убивает процесс, тогда yes
получает ошибку записи на выходе ./MyScript.sh
. Других вариантов нет, если вы используете программу yes
.
SIGPIPE
сигнал и EPIPE
ошибка сообщают ту же самую информацию - труба сломана. Если SIGPIPE
были включены для процесса yes
, вы не увидели бы ошибку. И только потому, что вы это видите; ничего нового не происходит. Это просто означает, что ./MyScript.sh
вышел (успешно или безуспешно - не имеет значения).
Ответ 2
Вы пытаетесь использовать программу yes для подключения к script? или эхо да к script? Если процесс работает через jenkins, добавьте "; true" в конец вашей команды оболочки.
Ответ 3
Так как yes
и ./MyScript.sh
могут запускаться в явном подоболочке, можно выполнить команду yes
, отправить yespid
в подглазу ./MyScript.sh
, а затем реализовать ловушку на EXIT
чтобы вручную завершить команду yes
. (Ловушка на EXIT
всегда должна быть реализована в подоболочке последней команды последовательной последовательности каналов).
# avoid hangup or "broken pipe" error message when parent process set SIGPIPE to be ignored
# sleep 0 or cat /dev/null: do nothing but with external command (for a shell builtin command see: help :)
(
trap "" PIPE
( (sleep 0; exec yes) & echo ${!}; wait ${!} ) |
(
trap 'trap - EXIT; kill "$yespid"; exit 0' EXIT
yespid="$(head -n 1)"
head -n 10 # replacement for ./MyScript.sh
)
echo ${PIPESTATUS[*]}
)
Если вы хотите выйти из подклассов yes
с кодом выхода 0
, вы также можете сделать это:
# avoid hangup or "broken pipe" error message when parent process set SIGPIPE to be ignored
# set exit code of yes subshell to 0
(
trap "" PIPE
(
trap 'trap - TERM; echo "kill from yes subshell ..." 1>&2; kill "${!}"; exit 0' TERM
subshell_pid="$(bash -c 'echo "$PPID"')"
(sleep 0; exec yes) & echo "${subshell_pid}"; wait ${!}
) |
(
trap 'trap - EXIT; kill -s TERM "$subshell_pid"; exit' EXIT
subshell_pid="$(head -n 1)"
head -n 10 # replacement for ./MyScript.sh
)
echo ${PIPESTATUS[*]}
)
Ответ 4
У меня была эта ошибка, и моя проблема с этим не в том, что она выводит yes: standard output: Broken pipe
, а скорее возвращает код ошибки.
Поскольку я запускаю свой script с bash строгий режим, включая -o pipefail
, когда да "ошибки" он вызывает мой script к ошибке.
Как избежать ошибки
То, как я избегал этого, выглядит так:
bash -c "yes || true" | my-script.sh
Ответ 5
Команда yes работает в бесконечном цикле. Я полагал, что это может быть решением:
yes | head -1 | ./MyScript.sh #only one "Y" would be output of the command yes
Но у меня такая же ошибка.
Мы можем перенаправить ошибку в /dev/null, как это предложено в @J.F. Себастьян, или убедитесь, что команда верна:
yes | head -1 | ./MyScript.sh || yes
Но эти предложения были менее оценены. Итак, мне пришлось создать свой собственный именованный канал, как показано ниже:
mkfifo /tmp/my_fifo #to create the named pipe
exec 3<>/tmp/my_fifo #to make the named pipe in read and write mode by assigning it to a file descriptor
echo "Y" >/tmp/my_fifo #to write into the named pipe, "Y" is the default value of yes
./MyScript.sh </tmp/my_fifo #to read from the named pipe
rm /tmp/my_fifo #remove the named pipe
Я ожидаю более ценные решения с большими объяснениями.
Здесь это объяснение для файлового дескриптора в Linux.
Спасибо