Linux bash:静默杀死后台函数进程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5719030/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 03:43:29  来源:igfitidea点击:

bash: silently kill background function process

linuxbashshellunixscripting

提问by rouble

shell gurus,

贝壳大师,

I have a bash shell script, in which I launch a background function, say foo(), to display a progress bar for a boring and long command:

我有一个 bash shell 脚本,我在其中启动了一个后台函数,比如说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

now, when foodies, I see the following text:

现在,当foo死亡时,我看到以下文字:

/home/user/script: line XXX: 30290 Killed                  foo

This totally destroys the awesomeness of my, otherwise massively cool, progress bar display.

这完全破坏了我的,否则非常酷的进度条显示的惊人之处。

How do I get rid of this message?

我如何摆脱这个消息?

采纳答案by Mark Edgar

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

BTW, I don't know about your massively cool progress bar, but have you seen Pipe Viewer (pv)? http://www.ivarch.com/programs/pv.shtml

顺便说一句,我不知道你的非常酷的进度条,但是你见过 Pipe Viewer (pv) 吗? http://www.ivarch.com/programs/pv.shtml

回答by rouble

Try to replace your line kill $foo_pid >/dev/null 2>&1with the line:

尝试kill $foo_pid >/dev/null 2>&1用以下行替换您的行:

(kill $foo_pid 2>&1) >/dev/null

Update:

更新

This answer is not correct for the reason explained by @mklement0 in his comment:

由于@mklement0 在他的评论中解释的原因,这个答案是不正确的:

The reason this answer isn't effective with background jobs is that Bash itself asynchronously, after the kill command has completed, outputs a status message about the killed job, which you cannot suppress directly - unless you use wait, as in the accepted answer.

这个答案对后台作业无效的原因是 Bash 本身异步地,在 kill 命令完成后,输出关于被杀死的作业的状态消息,你不能直接抑制 - 除非你使用等待,如接受的答案。

回答by rouble

This "hack" seems to work:

这个“黑客”似乎有效:

# 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

and it was inspired from here. World order has been restored.

它的灵感来自这里。世界秩序已经恢复。

回答by jilles

Add at the start of the function:

在函数的开头添加:

trap 'exit 0' TERM

回答by bbbco

This is a solution I came up with for a similar problem (wanted to display a timestamp during long running processes). This implements a killsub function that allows you to kill any subshell quietly as long as you know the pid. Note, that the trap instructions are important to include: in case the script is interrupted, the subshell will not continue to run.

这是我针对类似问题提出的解决方案(希望在长时间运行的进程中显示时间戳)。这实现了一个 killsub 函数,只要你知道 pid,它就允许你安静地杀死任何子 shell。请注意,陷阱指令很重要,包括:如果脚本被中断,子shell 将不会继续运行。

foo()
{
    while [ 1 ]
    do
        #massively cool progress bar display code
        sleep 1
    done
}

#Kills the sub process quietly
function killsub() 
{

    kill -9  2>/dev/null
    wait  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

回答by Mike Q

Another way to do it:

另一种方法:

    func_terminate_service(){

      [[ "$(pidof )" ]] && killall 
      sleep 2
      [[ "$(pidof )" ]] && kill -9 "$(pidof )" 

    }

call it with

用它来称呼它

    func_terminate_service "firefox"

回答by phily

Yet another way to disable job notifications is to put your command to be backgrounded in a sh -c 'cmd &'construct.

另一种禁用作业通知的方法是将您的命令置于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 ""; foo & echo ${!}' _ "$arg1" | head -1`


sleep 3
echo kill ${foo_pid}
kill ${foo_pid}
sleep 3
exit

回答by pix

Just came across this myself, and realised "disown" is what we are looking for.

我自己刚刚遇到了这个,并意识到“disown”是我们正在寻找的。

foo &
foo_pid=$!
disown

boring_and_long_command
kill $foo_pid
sleep 10

The death message is being printed because the process is still in the shells list of watched "jobs". The disown command will remove the most recently spawned process from this list so that no debug message will be generated when it is killed, even with SIGKILL (-9).

正在打印死亡消息,因为该进程仍在监视的“作业”的 shell 列表中。disown 命令将从该列表中删除最近产生的进程,这样即使使用 SIGKILL (-9) 也不会在它被杀死时生成调试消息。

回答by AhmadAssaf

You can use set +mbefore to suppress that. More information on that here

您可以使用set +mbefore 来抑制它。更多信息在这里