如何解决如何评估 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 会发生变化。
这里是我的问题:
- 额外的 PID 来自哪里?
- 如果出现我想杀死的进程没有运行的情况(或者为什么 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
请注意,pkill
、killall
、pgrep
等工具的性能与 ps -e | grep
类似。因此,如果您执行 pkill sh
,它会尝试杀死 sh
、bash
、ssh
等,因为它们都与模式匹配。
但是要回答有关在输入中没有任何内容时跳过 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.
,
此答案适用于 killall
或 pkill
(在 this answer 中建议)对您来说不够用的情况。例如,如果您真的想打印 "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"
使用 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 举报,一经查实,本站将立刻删除。