微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

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

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

提取 PID 需要 sed 步骤)。

但是,可能存在没有 xpdf-process 正在运行的情况。然后将行嵌入到脚本中会很困难,因为它会立即中止并带有来自 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

运行上面的脚本时我得到

$ Kill_ps
+ test=
+ echo 'test = <  >'
test = <  >
++ ps -e
++ grep xpdf
++ sed -n -e 's/^[^0-9]*\([0-9]*\)[^0-9]\{1,\}.*$/\1/p'
+ test='21538
24654
24804
24805'
+ echo 'test = < 21538
24654
24804
24805 >'
test = < 21538
24654
24804
24805 >
+ '[' -z '21538
24654
24804
24805' ']'
+ xargs '-d ' kill -SIGTERM
+ echo '21538
24654
24804
24805'
kill: Failed to parse argument: '21538
24654
24804
24805

发生了一些意外:在测试中,PID 多于进程

出现提示

$ ps -e | grep xpd
21538 pts/3    00:00:00 xpdf.real
24654 pts/2    00:00:00 xpdf.real

再次运行脚本时,24* PID 会发生变化。

这里是我的问题:

  1. 额外的 PID 来自哪里?
  2. 如果出现我想杀死的进程没有运行的情况(或者为什么 xargs 不接受 echo "$test" 作为输入),我该怎么办? (我希望我的脚本不会被中止)

提前致谢。

解决方法

您可以使用 pkill(1)killall(1) 代替解析 ps 输出。 (不建议为编写脚本而解析人类可读的输出。This 是一个示例。)

用法:

 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

请注意,pkillkillallpgrep 等工具的性能与 ps -e | grep 类似。因此,如果您执行 pkill sh,它会尝试杀死 shbashssh 等,因为它们都与模式匹配。

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

   -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.
,

此答案适用于 killallpkill(在 this answer 中建议)对您来说不够用的情况。例如,如果您真的想打印 "xpdf läuft nicht",如果没有要杀死的 pid 或应用 kill -SIGTERM,因为您想确定发送给 pid 的信号或其他什么。

您可以使用 bash 循环代替 xargssed。迭代 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"

使用 pgrep 有一种更快的方法(前一个是为了说明如何使用 bash 迭代基于列的命令输出):

count=0
while read -r; do
  kill -SIGTERM $REPLY
  (( count++ ))
done < <(pgrep xpdf)
[[ $count -le 0 ]] && echo "xpdf läuft nicht"

如果您的 xargs 版本可以为您提供 --no-run-if-empty,您仍然可以将它与 pgrep 一起使用(如 this answer 中建议的那样),但它在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"}}'

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。