Как подавить завершенное сообщение после убийства в bash?

Как вы можете подавить сообщение Terminated, которое появляется после того, как вы убиваете процесс в сценарии bash?

Я попробовал set +bm, но это не сработало.

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

Его следует объединить с stackoverflow.com/questions/5719030/…, который более обширен, но имеет больше ответов, чем этот.

tripleee 06.04.2017 10:03
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
64
1
51 987
13
Перейти к ответу Данный вопрос помечен как решенный

Ответы 13

Может быть, отделить процесс от текущего процесса оболочки, вызвав disown?

disown подразумевает, что оболочка не отправляет SIGHUP дочернему элементу при завершении, см. этот вопрос. Вот отвечать.

x-yuri 24.05.2013 19:09
Ответ принят как подходящий

Короткий ответ: вы не можете. 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 в подоболочке. Разве это не значит, что это не повлияет на скрипт, поскольку он выполняется в подоболочке? Таким образом не работает мой сценарий?

user14437 17.09.2008 14:34

Это неверный ответ. См. Ответ Марка Эдгара ниже.

Bruno Bronosky 25.02.2015 21:15

disown поступил как раз для меня - exec 3> & 2 рискованно по множеству причин - set + bm, похоже, не работал внутри скрипта, только в командной строке

disown подразумевает, что оболочка не отправляет SIGHUP дочернему элементу при завершении, см. этот вопрос. Вот отвечать.

x-yuri 24.05.2013 19:12

Решение: используйте SIGINT (работает только в неинтерактивных оболочках)

Демо:

cat > silent.sh <<"EOF"
sleep 100 &
kill -INT $!
sleep 1
EOF

sh silent.sh

http://thread.gmane.org/gmane.comp.shells.bash.bugs/15798

Чтобы отключить сообщение, вы должны перенаправить stderrв момент создания сообщения. Поскольку команда kill отправляет сигнал и не ждет ответа целевого процесса, перенаправление stderr команды kill не принесет вам пользы. Встроенная в bash wait была создана специально для этой цели.

Вот очень простой пример, который убивает самую последнюю фоновую команду. (Узнать больше о $! здесь.)

kill $!
wait $! 2>/dev/null

Поскольку и kill, и wait принимают несколько pid, вы также можете выполнять пакетное уничтожение. Вот пример, который убивает все фоновые процессы (конечно, текущего процесса / скрипта).

kill $(jobs -rp)
wait $(jobs -rp) 2>/dev/null

Меня привели сюда из bash: тихо убить процесс фоновой функции.

Круто, но он устанавливает статус выхода ($?) на какое-то странное значение

Alexander Shcheblikin 03.10.2014 01:03

@AlexanderShcheblikin wait возвращает код выхода фонового процесса, или 128 + (номер сигнала, который его убил).

Henk Langeveld 09.12.2014 00:57

Это вообще неверно. Сообщение создается не на wait, а всякий раз, когда вызывается wait_for() (на jobs.c), что означает, что оно может быть сгенерировано, когда задание переднего плана любой завершается. Попробуйте это: sleep 10 & kill %1; sleep 0; wait 2>/dev/null. Ответ wnoise в этом отношении в основном правильный. Единственный способ полностью подавить сообщение - выполнить exec 2>/dev/null, последствия которого очевидны.

alecov 16.11.2019 23:20

Это то, что мы все ищем?

Нежелательный:

$ 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 подоболочка? Также принятый ответ уже содержит информацию, которую вы дали.

matthias krull 05.10.2012 22:10

Как намекал Матиас, этот ответ неверен. Bash не отображает сообщения управления заданиями для команд, выполняемых в подоболочке, поэтому установка режима монитора для этого бесполезна. (set +m; sleep 3 &) будет производить точно такой же эффект, как и (sleep 3 &).

Six 04.03.2015 21:38

Это также работает для killall (для тех, кто его предпочитает):

killall -s SIGINT (yourprogram) 

подавляет сообщение ... Я запускал mpg123 в фоновом режиме. Его можно было убить только молча, отправив ctrl-c (SIGINT) вместо SIGTERM (по умолчанию).

То, как именно программа реагирует на различные сигналы, также во многом зависит от этой программы.

tripleee 06.04.2017 10:06

На основе Ответ Марка. Я использовал kill -INT, как он предлагает, с некоторым успехом, но заметил, что он не убивал некоторые процессы. После тестирования некоторых других сигналов я вижу, что SIGPIPE также убьет без сообщения.

kill -PIPE

или просто

kill -13

Я не считаю -13 "проще", чем -PIPE :-)

MarcH 18.12.2015 01:46

Это совершенно неправильно, процесс может настраивать обработчики сигналов и использовать их по своему усмотрению. В частности, сигнал PIPE часто перехватывается при использовании сокетов. Сигнал TERM по умолчанию должен использоваться для того, чтобы процессы ASK завершились, процесс также может поймать его и проигнорировать или выполнить очистку, а затем завершить работу без ошибок.

Moshe Gottlieb 06.12.2017 19:28

Не общий ответ, потому что SIGPIPE может быть перехвачен, но он работает во многих случаях, когда SIGPIPE не обрабатывается дочерним процессом.

Eric 18.04.2018 12:37

Я перепробовал все решения, только kill -13 pid будет молчать информацию kill по умолчанию

Lampard 21.12.2019 02:50

Другой способ отключить уведомления о заданиях - поместить вашу команду в конструкцию 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. См. Ответ Марка Эдгара, чтобы узнать, как это сделать правильно.

Bruno Bronosky 25.02.2015 21:21

Я обнаружил, что добавление команды kill в функцию и последующее выделение функции в фоновом режиме подавляет вывод завершения.

function killCmd() {
    kill 
}

killCmd $somePID &

Нет, не работает: bash по-прежнему выводит сообщение при первой же возможности, когда дочерний процесс завершен.

Eric 18.04.2018 12:32

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]'

Другие вопросы по теме