Как подавить завершенное сообщение после завершения работы в bash?
Вопрос
Как вы можете подавлять Terminated
сообщение, которое появляется после завершения
процесса в скрипте bash?
Я пытался set +bm
, но это не работает.
Я знаю, что другое решение включает в себя вызов exec 2> /dev/null
, но является ли это
надежным?Как мне сбросить его обратно, чтобы я мог продолжать видеть stderr?
Решение
Короткий ответ заключается в том, что вы не можете.Bash всегда выводит статус заданий переднего плана.Флаг мониторинга применяется только к фоновым заданиям и только для интерактивных оболочек, а не скриптов.
смотрите функцию notify_of_job_status() в jobs.c.
Как вы говорите, вы можете перенаправить, чтобы стандартная ошибка указывала на /dev/null, но тогда вы пропустите любые другие сообщения об ошибках.Вы можете сделать это временным, выполнив перенаправление в подоболочке, которая запускает скрипт.Это оставляет в покое исходное окружение.
(script 2> /dev/null)
который потеряет все сообщения об ошибках, но только из этого скрипта, а не из чего-либо еще, запущенного в этой оболочке.
Вы можете сохранить и восстановить стандартную ошибку, перенаправив новый filedescriptor, чтобы указать там:
exec 3>&2 # 3 is now a copy of 2
exec 2> /dev/null # 2 now points to /dev/null
script # run script with redirected stderr
exec 2>&3 # restore stderr to saved
exec 3>&- # close saved version
Но я бы не рекомендовал это - единственным плюсом первого варианта является то, что он сохраняет вызов вложенной оболочки, будучи при этом более сложным и, возможно, даже изменяя поведение скрипта, если скрипт изменяет файловые дескрипторы.
Редактировать:
Для получения более подходящего ответа проверьте ответ, данный Марк Эдгар
Другие советы
Чтобы отключить сообщение, вы должны перенаправить его stderr
в момент создания сообщения.Потому что kill
команда отправляет сигнал и, не дожидаясь ответа целевого процесса, перенаправляет stderr
из числа kill
командование не приносит тебе никакой пользы.Встроенный bash wait
был создан специально для этой цели.
Вот очень простой пример, который убивает самую последнюю фоновую команду.(Узнайте больше о $!вот.)
kill $!
wait $! 2>/dev/null
Потому что оба kill
и wait
принимая несколько pid-адресов, вы также можете выполнять пакетные уничтожения.Вот пример, который убивает все фоновые процессы (текущего процесса / скрипта, конечно).
kill $(jobs -rp)
wait $(jobs -rp) 2>/dev/null
Меня привели сюда из удар:бесшумно отключите фоновую функцию процесса.
Вдохновленный Ответ Марча.Я использовал kill -INT
как он предполагает, с некоторым успехом, но я заметил, что это не убивало некоторые процессы.После тестирования некоторых других сигналов я вижу, что SIGPIPE
убьет так же и без сообщения.
kill -PIPE
или просто
kill -13
Решение:используйте SIGINT (работает только в неинтерактивных оболочках)
ДЕМОНСТРАЦИЯ:
cat > silent.sh <<"EOF"
sleep 100 &
kill -INT $!
sleep 1
EOF
sh silent.sh
Возможно, отделите процесс от текущего процесса оболочки, вызвав disown
?
Это то, что мы все ищем?
Нежеланный:
$ sleep 3 &
[1] 234
<pressing enter a few times....>
$
$
[1]+ Done sleep 3
$
Желанный:
$ (set +m; sleep 3 &)
<again, pressing enter several times....>
$
$
$
$
$
Как вы можете видеть, сообщения об окончании задания нет.Работает у меня и в скриптах bash, в том числе для убитых фоновых процессов.
'set + m' отключает управление заданиями (см. "набор справочных данных") для текущей командной строки.Таким образом, если вы введете свою команду в подоболочку (как это сделано здесь в скобках), вы не повлияете на настройки управления заданиями текущей оболочки.Единственным недостатком является то, что вам нужно вернуть pid вашего фонового процесса обратно в текущую оболочку, если вы хотите проверить, был ли он завершен, или оценить код возврата.
Другой способ отключить уведомления о заданиях - поместить вашу команду в качестве фона в sh -c 'cmd &'
сконструировать.
#!/bin/bash
# ...
pid="`sh -c 'sleep 30 & echo ${!}' | head -1`"
kill "$pid"
# ...
# or put several cmds in sh -c '...' construct
sh -c '
sleep 30 &
pid="${!}"
sleep 5
kill "${pid}"
'
Это также работает для killall (для тех, кто предпочитает его):
killall -s SIGINT (yourprogram)
подавляет сообщение...Я запускал mpg123 в фоновом режиме.Его можно было уничтожить только беззвучно, отправив ctrl-c (SIGINT) вместо SIGTERM (по умолчанию).
disown поступил совершенно правильно для меня - exec 3> & 2 рискован по многим причинам - set + bm, похоже, не работал внутри скрипта, только в командной строке
Добился успеха с добавлением 'jobs 2>&1 >/dev/null
что касается сценария, не уверен, поможет ли это чьему-либо другому сценарию, но вот пример.
while true; do echo $RANDOM; done | while read line
do
echo Random is $line the last jobid is $(jobs -lp)
jobs 2>&1 >/dev/null
sleep 3
done
Я обнаружил, что помещение команды kill в функцию, а затем фоновое выполнение функции подавляет вывод завершения
function killCmd() {
kill $1
}
killCmd $somePID &
Простой:
{ kill $! } 2>/dev/null
Преимущество?может использовать любой сигнал
бывший:
{ kill -9 $PID } 2>/dev/null