如何在bash脚本中评估管道的结果

如何在bash脚本中评估管道的结果,bash,pipe,kill,Bash,Pipe,Kill,我需要以下问题的帮助: 我想杀死一个程序的所有实例,比如说xpdf。 在提示下,以下工作按预期进行: $ ps -e | grep xpdf | sed -n -e "s/^[^0-9]*\([0-9]*\)[^0-9]\{1,\}.*$/\1/p" | xargs kill -SIGTERM 提取PID需要sed步骤 但是,可能存在没有运行xpdf进程的情况。然后,将该行嵌入到脚本中是很困难的,因为它会立即终止,并带有来自kill的消息。我能怎么办 我试着写剧本 #!/b

我需要以下问题的帮助: 我想杀死一个程序的所有实例,比如说xpdf。 在提示下,以下工作按预期进行:

$ ps -e | grep xpdf | sed -n -e "s/^[^0-9]*\([0-9]*\)[^0-9]\{1,\}.*$/\1/p" | xargs kill -SIGTERM
提取PID需要sed步骤

但是,可能存在没有运行xpdf进程的情况。然后,将该行嵌入到脚本中是很困难的,因为它会立即终止,并带有来自kill的消息。我能怎么办

我试着写剧本

#!/bin/bash
#
set -x
test=""
echo "test = < $test >"
test=`ps -e | grep xpdf | sed -n -e "s/^[^0-9]*\([0-9]*\)[^0-9]\{1,\}.*$/\1/p"`
echo "test = < $test >"
if [ -z "$test" ]; then echo "xpdf läuft nicht";
else echo "$test" | xargs -d" " kill -SIGTERM
fi
再次运行脚本时,24*PID会发生变化

下面是我的问题:

额外的PID来自哪里? 我能做些什么来处理这种情况,在这种情况下,我不想杀死任何正在运行的进程,或者为什么xargs不接受echo$test作为输入?我希望我的脚本不会被中止
提前感谢。

此答案适用于中建议的killall或pkill对您来说还不够的情况。例如,如果您真的想打印xpdf läuft nicht,如果没有要终止的pid或应用kill-SIGTERM,因为您想确定发送给pid的信号或其他信息

可以使用bash循环而不是xargs和sed。迭代CSV/列输出非常简单:

count=0
while read -r uid pid ppid trash; do
  kill -SIGTERM $pid
  (( count++ ))
done < <(ps -ef|grep xpdf)
[[ $count -le 0 ]] && echo "xpdf läuft nicht"
如果您的xargs版本可以为您提供-no run If empty,您仍然可以像中建议的那样将其与pgrep一起使用,但在BSD或POSIX版本中不可用。这是我在macOS上的例子

awk也可以在管道后只使用一个命令来完成此任务:

ps -ef|awk 'BEGIN {c="0"} {if($0 ~ "xpdf" && !($0 ~ "awk")){c++; system("kill -SIGTERM "$2)}} END {if(c <= 0){print "xpdf läuft nicht"}}'
您可以使用或代替解析ps输出。不建议为脚本分析人类可读的输出。这就是一个例子

用法:

 pkill xpdf
 killall xpdf # Note that on solaris, it kills all the processes that you can kill. https://unix.stackexchange.com/q/252349#comment435182_252356
 pgrep xpdf # Lists pids
 ps -C xpdf -o pid=  # Lists pids
请注意,像pkill、killall、pgrep这样的工具的性能与ps-e|grep类似。因此,如果您执行pkill-sh,它将尝试杀死sh、bash、ssh等,因为它们都匹配该模式

但是要回答您关于在输入上没有任何内容时跳过xargs运行的问题,您可以对GNU xargs使用-r选项


xargs-r kill-SIGTERM?xargs-r:-如果为空,则不运行。顺便说一句,你为什么不使用/来代替?有什么复杂的地方吗?一个额外的pid来自您的grep命令,它有xpdf这个术语。如果使用xargs-n 1 kill-TERM,脚本将无法达到最佳效果。当我们将ls放在一边时,不建议对命令的输出进行迭代,该命令的输出可能包含$cmd循环中带有for i的空格。然而,cmd | while read-r或awk非常适合解析基于列或CSV的输出。我在这里写过:顺便说一句,我同意在这种情况下使用killall或pkill,POSIX xargs不提供-如果扩展为空,则不运行,因此我将保留我自己的答案以防万一:正如我在回答中所说,-r是GNU扩展。FWIW,我没有否决你的答案。所以,请不要删除它。当直接工具可用时,请避免解析。此外,cmd的输出必须可靠且不可破解。e、 g.对于ps,我不知道进程名称中的不可打印字符是否总是打印为?或者它只是ps安装在我的系统上。此外,我还看到一些非标准unix(如发行版)上的ps输出列有所不同。所以,我尽量不依赖这样的解析。建议作为我问题的解决方案。@GIC很高兴我能提供帮助。如果您的问题已经解决,请毫不犹豫地选择您想要的答案并在“已解决”处进行标记。一个小小的更正:while将打开一个子shell,因此while循环后的count=0请参见。所以,这一部分没有work@GIC是的,你完全正确。因此,我用另一种方法更新了我的答案,在不打开子shell的情况下,在读取命令输出时使用循环。如果不需要保留计数,则可以在读取时保留cmd |。
count=0
while read -r; do
  kill -SIGTERM $REPLY
  (( count++ ))
done < <(pgrep xpdf)
[[ $count -le 0 ]] && echo "xpdf läuft nicht"
ps -ef|awk 'BEGIN {c="0"} {if($0 ~ "xpdf" && !($0 ~ "awk")){c++; system("kill -SIGTERM "$2)}} END {if(c <= 0){print "xpdf läuft nicht"}}'
 pkill xpdf
 killall xpdf # Note that on solaris, it kills all the processes that you can kill. https://unix.stackexchange.com/q/252349#comment435182_252356
 pgrep xpdf # Lists pids
 ps -C xpdf -o pid=  # Lists pids
   -r, --no-run-if-empty
          If the standard input does not contain any nonblanks, do not run the command.
          Normally, the command is run once even if there is no input.
          This option is a GNU extension.