Ответ 1
kill $foo_pid
wait $foo_pid 2>/dev/null
Кстати, я не знаю о вашем массовом прохладном баре прогресса, но вы видели Pipe Viewer (pv)? http://www.ivarch.com/programs/pv.shtml
Гуру оболочки,
У меня есть оболочка bash script, в которой я запускаю функцию фона, скажем foo()
, чтобы отобразить индикатор выполнения для скучной и длинной команды:
foo()
{
while [ 1 ]
do
#massively cool progress bar display code
sleep 1
done
}
foo &
foo_pid=$!
boring_and_long_command
kill $foo_pid >/dev/null 2>&1
sleep 10
теперь, когда foo
умирает, я вижу следующий текст:
/home/user/script: line XXX: 30290 Killed foo
Это полностью разрушает удивительность моего, в противном случае массивного охлаждения, индикатора выполнения.
Как мне избавиться от этого сообщения?
kill $foo_pid
wait $foo_pid 2>/dev/null
Кстати, я не знаю о вашем массовом прохладном баре прогресса, но вы видели Pipe Viewer (pv)? http://www.ivarch.com/programs/pv.shtml
Просто натолкнулся на это сам, и осознанное "отречение" - это то, что мы ищем.
foo &
foo_pid=$!
disown
boring_and_long_command
kill $foo_pid
sleep 10
Сообщение о смерти печатается, потому что процесс все еще находится в списке оболочек наблюдаемых "заданий". Команда disown удалит последний из созданных процессов из этого списка, чтобы отладочное сообщение не было сгенерировано, когда оно было убито, даже с SIGKILL (-9).
Попробуйте заменить строку kill $foo_pid >/dev/null 2>&1
на строку:
(kill $foo_pid 2>&1) >/dev/null
Обновление
Этот ответ неверен по причине, объясненной @mklement0 в его комментарии:
Причина, по которой этот ответ неэффективен для фоновых заданий, заключается в том, что Bash сам асинхронно, после завершения команды kill, выводит сообщение о состоянии убитого задания, которое вы не можете подавлять напрямую - если вы не используете wait, как в принятом ответе.
Это решение, с которым я столкнулся с подобной проблемой (хотел показать временную метку во время длительных процессов). Это реализует функцию killsub, которая позволяет вам убить любую подоболочку тихо, пока вы знаете pid. Обратите внимание, что команды trap важны для включения: в случае прерывания script, подоболочка не будет продолжать работать.
foo()
{
while [ 1 ]
do
#massively cool progress bar display code
sleep 1
done
}
#Kills the sub process quietly
function killsub()
{
kill -9 ${1} 2>/dev/null
wait ${1} 2>/dev/null
}
foo &
foo_pid=$!
#Add a trap incase of unexpected interruptions
trap 'killsub ${foo_pid}; exit' INT TERM EXIT
boring_and_long_command
#Kill foo after finished
killsub ${foo_pid}
#Reset trap
trap - INT TERM EXIT
Этот "взлом", похоже, работает:
# Some trickery to hide killed message
exec 3>&2 # 3 is now a copy of 2
exec 2> /dev/null # 2 now points to /dev/null
kill $foo_pid >/dev/null 2>&1
sleep 1 # sleep to wait for process to die
exec 2>&3 # restore stderr to saved
exec 3>&- # close saved version
и он был вдохновлен здесь. Мировой порядок восстановлен.
Добавить в начале функции:
trap 'exit 0' TERM
В отношении использования "wait": это лучший ответ, который я думаю. См. fooobar.com/questions/121227/... для примера того, как это выглядит/работает.
Другой способ сделать это:
func_terminate_service(){
[[ "$(pidof ${1})" ]] && killall ${1}
sleep 2
[[ "$(pidof ${1})" ]] && kill -9 "$(pidof ${1})"
}
назовите его
func_terminate_service "firefox"
Еще один способ отключить уведомления о работе - это включить в команду sh -c 'cmd &'
команду для создания вашей команды.
#!/bin/bash
foo()
{
while [ 1 ]
do
sleep 1
done
}
#foo &
#foo_pid=$!
export -f foo
foo_pid=`sh -c 'foo & echo ${!}' | head -1`
# if shell does not support exporting functions (export -f foo)
#arg1='foo() { while [ 1 ]; do sleep 1; done; }'
#foo_pid=`sh -c 'eval "$1"; foo & echo ${!}' _ "$arg1" | head -1`
sleep 3
echo kill ${foo_pid}
kill ${foo_pid}
sleep 3
exit
Вы можете использовать set +m
прежде, чтобы подавить это. Больше информации об этом здесь