脚本:
#!/usr/bin/env bash
set -e
set -u
set -x
set -o pipefail
hosts=(
host1
host2
)
for host in ${hosts[@]}
do
ssh $host 'pids=$(ps -aux|pgrep -f "/usr/bin/nmon"); kill $pids; wait $pids 2>/dev/null'
done
输出:
+ for host in '${hosts[@]}'
+ ssh host1 'pids=$(ps -aux|pgrep -f "/usr/bin/nmon" |awk "{print $2}") ; kill $pids ; wait $pids 2>/dev/null'
Killed by signal 15.
我已经使用过wait
捕获信号,但还是不起作用?
任何帮助都将不胜感激!
答案1
我认为这里发生的事情是pgrep -f "/usr/bin/nmon"
也匹配运行该命令的 shell,因为它会在完整命令行中找到字符串“/usr/bin/nmon”,并且您指定 -f 在整个命令行中查找字符串(而不仅仅是进程名称......)
您的脚本中有很多不正确的地方:
ps -aux|pgrep -f "/usr/bin/nmon"
或者:
ps -aux|pgrep -f "/usr/bin/nmon" |awk "{print $2}"
这完全是错误的。pgrep 可以独立工作,不需要任何管道。ps ... | grep ...
是一个东西,但是 pgrep 会在进程列表本身中查找模式,因此不需要ps
。您也不需要awk
剪切字段,因为 pgrep 已经只返回了 PID。
然后:
kill $pids
不要使用 pgrep 查找 pid,然后用单独的命令杀死它们……相反,直接使用 pkill 就好!pkill 是 pgrep 的兄弟,它将查找进程并向它们发送终止信号。您甚至可以看到 pgrep 和 pkill 共享相同的手册页因为它们非常相似。
wait $pids
这也行不通……因为你只能调用wait
当前进程的子进程。你不能在任何进程上调用它。考虑到你刚刚通过 ssh 打开了这个 shell,你真的不能等待这些已经存在的进程……
因此,简而言之:没有管道,直接使用 pkill,省略 -f(因此它只匹配 /usr/bin/nmon 命令)并且不要等待:
for host in "${hosts[@]}" ; do
ssh "$host" pkill /usr/bin/nmon
done
简单的!
我还为您修复了 shell 引用... 简而言之:您需要对所有扩展为单个单词的变量使用双引号。好吧,数组也一样。
我希望这有帮助!