如何评估 bash 脚本中管道的结果
How to evaluate results of pipes in a bash script
我需要帮助解决以下问题:
我想杀死一个程序的所有实例,比方说 xpdf。
在提示符下,以下内容按预期工作:
$ ps -e | grep xpdf | sed -n -e "s/^[^0-9]*\([0-9]*\)[^0-9]\{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,\}.*$//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,\}.*$//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"
作为输入)? (我希望我的脚本不被中止)
提前致谢。
此答案适用于 killall
或 pkill
( 中建议)对您来说不够的情况。例如,如果你真的想打印 "xpdf läuft nicht"
如果没有 pid 可以杀死或应用 kill -SIGTERM
因为你想确定你发送给你的 pids 或其他什么的信号。
您可以使用 bash 循环代替 xargs
和 sed
。迭代 CSV/column 输出非常简单:
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
一起使用(如 中的建议),但事实并非如此在 BSD 或 POSIX 版本上可用。例如我在 macOS 上的情况...
awk
也可以做到这一点(管道后只有一个命令):
ps -ef|awk 'BEGIN {c="0"} {if([=12=] ~ "xpdf" && !([=12=] ~ "awk")){c++; system("kill -SIGTERM ")}} END {if(c <= 0){print "xpdf läuft nicht"}}'
你可以用pkill(1)
or killall(1)
instead of parsing ps
output. (Parsing human-readable output for scripting is not recommended. 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.
我需要帮助解决以下问题: 我想杀死一个程序的所有实例,比方说 xpdf。 在提示符下,以下内容按预期工作:
$ ps -e | grep xpdf | sed -n -e "s/^[^0-9]*\([0-9]*\)[^0-9]\{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,\}.*$//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,\}.*$//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"
作为输入)? (我希望我的脚本不被中止)
提前致谢。
此答案适用于 killall
或 pkill
("xpdf läuft nicht"
如果没有 pid 可以杀死或应用 kill -SIGTERM
因为你想确定你发送给你的 pids 或其他什么的信号。
您可以使用 bash 循环代替 xargs
和 sed
。迭代 CSV/column 输出非常简单:
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
一起使用(如
awk
也可以做到这一点(管道后只有一个命令):
ps -ef|awk 'BEGIN {c="0"} {if([=12=] ~ "xpdf" && !([=12=] ~ "awk")){c++; system("kill -SIGTERM ")}} END {if(c <= 0){print "xpdf läuft nicht"}}'
你可以用pkill(1)
or killall(1)
instead of parsing ps
output. (Parsing human-readable output for scripting is not recommended. 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.