Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux bash:静默地杀死后台函数进程_Linux_Bash_Shell_Unix_Scripting - Fatal编程技术网

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

Linux bash:静默地杀死后台函数进程,linux,bash,shell,unix,scripting,Linux,Bash,Shell,Unix,Scripting,贝壳大师 我有一个bashshell脚本,在这个脚本中我启动了一个后台函数,比如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

贝壳大师

我有一个bashshell脚本,在这个脚本中我启动了一个后台函数,比如
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\u pid>/dev/null 2>&1

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

由于@mklement0在其评论中解释的原因,此答案不正确:

这个答案对背景工作无效的原因是 kill命令完成后,异步Bash自身, 输出有关已终止作业的状态消息,但不能执行此操作 直接抑制-除非您使用等待,如在接受的答案中

这种“黑客”似乎奏效了:

# 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
它的灵感来自于。世界秩序已经恢复

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

顺便说一句,我不知道你的进度条有多酷,但你看过PipeViewer(pv)吗

在函数开头添加:

trap 'exit 0' TERM

这是我针对类似问题提出的解决方案(希望在长时间运行的进程中显示时间戳)。这实现了一个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 ${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
另一种方法是:

    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

我自己刚刚发现了这一点,并意识到“否认”是我们正在寻找的

foo &
foo_pid=$!
disown

boring_and_long_command
kill $foo_pid
sleep 10

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

您可以在之前使用
set+m
来抑制它。有关该错误的更多信息,错误消息应该来自默认的信号处理程序,该处理程序将信号源转储到脚本中。我只在Bash3.x和4.x上遇到了类似的错误。为了始终在任何地方安静地杀死子进程(在bash 3/4/5、dash、ash、zsh上测试),我们可以在子进程的第一个阶段捕获术语信号:

#/垃圾箱/垃圾箱
##假设脚本名为test.sh
foo(){
陷阱“退出0”项##这里是关键
虽然是真的,但一定要睡觉
}
在孩子面前回音
ps辅助“grep”测试\.s[h]\\\124; slee[p]'
福&
foo_pid=$!
睡眠1#等待陷阱完成
杀前回音
ps辅助“grep”测试\.s[h]\\\124; slee[p]'
杀死$foo_pid
睡眠1#等待杀戮结束
杀戮后的回声
ps辅助“grep”测试\.s[h]\\\124; slee[p]'

+1在re:a bash脚本中使用“massively cool:”)即使将kill foo_pid更改为kill$foo_pid,我也无法复制该脚本。@Tanktalus,我认为这是因为在将输出发送到stderr之前,脚本可能已死亡。我在伪代码的末尾添加了一个sleep,这应该可以让您重新创建问题。
while[1];do
可以写成
而:;do
。这应该与哪个更为集中,但缺少这里的一些答案合并。这是可行的,但不需要在
kill$foo_pid
之后添加
/dev/null 2>&1
部分作为stderr(这是不需要的文本的来源)在尝试终止不存在的进程以防止
kill foo\u pid失败时,已定向到/dev/nullhelp me:没有这样的进程
message@Koen. 是的,但这与背景工作无关。您可以使用
2>/dev/null
使
kill
本身发出的任何错误消息静音,就像任何命令一样。此答案对后台作业无效的原因是,Bash本身在
kill
命令完成后异步输出一条关于已终止作业的状态消息,您无法直接抑制该消息,除非您使用
wait
,如接受的答案所示。这对我不起作用。我仍然会收到“15号信号杀死”的信。我正试图通过ssh实现这一点——我启动一个会话并启动一个进程,然后再次使用ssh并终止该进程。当我尝试“wait$pid”时,它表示进程不是子进程(我认为这是一个不同的会话),然后“被信号15杀死”仍然写入终端。在这种情况下有没有办法抑制这种情况?很棒的东西;我建议
{kill$foo_-pid&&wait$foo_-pid;}2>/dev/null
,这样也可以在目标进程不再活动的情况下保持沉默。在
bash
完成
kill
命令之前,是否存在孩子死亡的(远程)可能性,这样就可以生成终止报告了吗?谢谢@mklement0-您还可以使用作业ID的
kill&&wait
模式:
{kill%1&&wait%1;}2>/dev/null
非常有效。我同意——这是Bash的最佳解决方案。然而,disown是Bash内置的命令,在大多数其他shell中不可用。@mattst:确实值得指出的是,
disown
不符合POSIX;但是,它也可以在
ksh
zsh
中找到。而且,使用
disown
似乎不仅仅意味着解除当前shell与后台进程的关联:@mklement0感谢您提供的信息。还有有趣的链接
nohup
实际上对于我目前使用
disown
的几个脚本来说是一个很好的解决方案。因为原始问题
disown
肯定是要使用的问题,我相信您已经意识到了。@mattst:
disown
对于手头的问题来说很好(如果终端过早死亡,后台作业将在下次尝试写入stdout时死亡),但是,鉴于问题的一般标题,