Как вы можете подавить сообщение Terminated, которое появляется после того, как вы убиваете
процесс в сценарии bash?
Я попробовал set +bm, но это не сработало.
Я знаю, что другое решение включает вызов exec 2> /dev/null, но разве это не так?
надежный? Как мне вернуть его обратно, чтобы я мог продолжать видеть stderr?





Может быть, отделить процесс от текущего процесса оболочки, вызвав disown?
disown подразумевает, что оболочка не отправляет SIGHUP дочернему элементу при завершении, см. этот вопрос. Вот отвечать.
Короткий ответ: вы не можете. Bash всегда выводит статус заданий переднего плана. Флаг мониторинга применяется только для фоновых заданий и только для интерактивных оболочек, но не для скриптов.
см. notify_of_job_status () в jobs.c.
Как вы говорите, вы можете перенаправить, поэтому стандартная ошибка указывает на / dev / null, но тогда вы пропустите любые другие сообщения об ошибках. Вы можете сделать это временным, выполнив перенаправление в подоболочке, которая запускает скрипт. Это оставляет исходную среду в покое.
(script 2> /dev/null)
который потеряет все сообщения об ошибках, но только из этого сценария, а не из чего-либо еще, запущенного в этой оболочке.
Вы можете сохранить и восстановить стандартную ошибку, перенаправив новый файловый дескриптор туда:
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 в подоболочке. Разве это не значит, что это не повлияет на скрипт, поскольку он выполняется в подоболочке? Таким образом не работает мой сценарий?
Это неверный ответ. См. Ответ Марка Эдгара ниже.
disown поступил как раз для меня - exec 3> & 2 рискованно по множеству причин - set + bm, похоже, не работал внутри скрипта, только в командной строке
disown подразумевает, что оболочка не отправляет SIGHUP дочернему элементу при завершении, см. этот вопрос. Вот отвечать.
Решение: используйте SIGINT (работает только в неинтерактивных оболочках)
Демо:
cat > silent.sh <<"EOF"
sleep 100 &
kill -INT $!
sleep 1
EOF
sh silent.sh
Чтобы отключить сообщение, вы должны перенаправить stderrв момент создания сообщения. Поскольку команда kill отправляет сигнал и не ждет ответа целевого процесса, перенаправление stderr команды kill не принесет вам пользы. Встроенная в bash wait была создана специально для этой цели.
Вот очень простой пример, который убивает самую последнюю фоновую команду. (Узнать больше о $! здесь.)
kill $!
wait $! 2>/dev/null
Поскольку и kill, и wait принимают несколько pid, вы также можете выполнять пакетное уничтожение. Вот пример, который убивает все фоновые процессы (конечно, текущего процесса / скрипта).
kill $(jobs -rp)
wait $(jobs -rp) 2>/dev/null
Меня привели сюда из bash: тихо убить процесс фоновой функции.
Круто, но он устанавливает статус выхода ($?) на какое-то странное значение
@AlexanderShcheblikin wait возвращает код выхода фонового процесса, или 128 + (номер сигнала, который его убил).
Это вообще неверно. Сообщение создается не на wait, а всякий раз, когда вызывается wait_for() (на jobs.c), что означает, что оно может быть сгенерировано, когда задание переднего плана любой завершается. Попробуйте это: sleep 10 & kill %1; sleep 0; wait 2>/dev/null. Ответ wnoise в этом отношении в основном правильный. Единственный способ полностью подавить сообщение - выполнить exec 2>/dev/null, последствия которого очевидны.
Это то, что мы все ищем?
Нежелательный:
$ 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 фонового процесса в текущую оболочку, если вы хотите проверить, завершился ли он, или оценить код возврата.
Зачем вам set +m подоболочка? Также принятый ответ уже содержит информацию, которую вы дали.
Как намекал Матиас, этот ответ неверен. Bash не отображает сообщения управления заданиями для команд, выполняемых в подоболочке, поэтому установка режима монитора для этого бесполезна. (set +m; sleep 3 &) будет производить точно такой же эффект, как и (sleep 3 &).
Это также работает для killall (для тех, кто его предпочитает):
killall -s SIGINT (yourprogram)
подавляет сообщение ... Я запускал mpg123 в фоновом режиме. Его можно было убить только молча, отправив ctrl-c (SIGINT) вместо SIGTERM (по умолчанию).
То, как именно программа реагирует на различные сигналы, также во многом зависит от этой программы.
На основе Ответ Марка. Я использовал kill -INT, как он предлагает, с некоторым успехом, но заметил, что он не убивал некоторые процессы. После тестирования некоторых других сигналов я вижу, что SIGPIPE также убьет без сообщения.
kill -PIPE
или просто
kill -13
Я не считаю -13 "проще", чем -PIPE :-)
Это совершенно неправильно, процесс может настраивать обработчики сигналов и использовать их по своему усмотрению. В частности, сигнал PIPE часто перехватывается при использовании сокетов. Сигнал TERM по умолчанию должен использоваться для того, чтобы процессы ASK завершились, процесс также может поймать его и проигнорировать или выполнить очистку, а затем завершить работу без ошибок.
Не общий ответ, потому что SIGPIPE может быть перехвачен, но он работает во многих случаях, когда SIGPIPE не обрабатывается дочерним процессом.
Я перепробовал все решения, только kill -13 pid будет молчать информацию kill по умолчанию
Другой способ отключить уведомления о заданиях - поместить вашу команду в конструкцию 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}"
'
Добился успеха с добавлением 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 $! } 2>/dev/null
Преимущество? может использовать любой сигнал
бывший:
{ kill -9 $PID } 2>/dev/null
kill (кроме -9) посылает сигнал и не ждет ответа. Если это работает для вас, это происходит через состояние гонки. Я также видел, как код переходил с { kill $! } 2>/dev/null на { kill $!; date } 2>/dev/null на { kill $!; sleep 5 } 2>/dev/null. См. Ответ Марка Эдгара, чтобы узнать, как это сделать правильно.
Я обнаружил, что добавление команды kill в функцию и последующее выделение функции в фоновом режиме подавляет вывод завершения.
function killCmd() {
kill
}
killCmd $somePID &
Нет, не работает: bash по-прежнему выводит сообщение при первой же возможности, когда дочерний процесс завершен.
Terminated регистрируется обработчиком сигналов по умолчанию для bash 3.x и 4.x. Просто перехватите сигнал TERM в самом первом дочернем процессе:
#!/bin/sh
## assume script name is test.sh
foo() {
trap 'exit 0' TERM ## here is the key
while true; do sleep 1; done
}
echo before child
ps aux | grep 'test\.s[h]\|slee[p]'
foo &
pid=$!
sleep 1 # wait trap is done
echo before kill
ps aux | grep 'test\.s[h]\|slee[p]'
kill $pid ## no need to redirect stdin/stderr
sleep 1 # wait kill is done
echo after kill
ps aux | grep 'test\.s[h]\|slee[p]'
Его следует объединить с stackoverflow.com/questions/5719030/…, который более обширен, но имеет больше ответов, чем этот.