Хадсон: "да: стандартный вывод: сломанная труба"

Мне нужно запустить оболочку 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.

Спасибо