我试图执行我的脚本,但是$ 1参数与最后一个管道的参数连接在一起,结果如下:
killProcess(){
ps aux |grep $1 | tr -s " " " " | awk "{printf \"%s \",\$2}" | tr " " "\n" | xargs -l1 echo $1
}
$killProcess node
node 18780
node 965856
node 18801
node 909028
node 19000
node 1407472
node 19028
node 583620
node 837
node 14804
node 841
node 14260
但是我只想要pids列表,而没有node参数能够删除它们,只有当我将其放在脚本下时才会发生,在命令行中它对我来说正常工作,因为我没有传递任何参数到脚本,它不会被串联。
答案 0 :(得分:3)
当前的问题是您不希望$1
结尾。在这种情况下,$1
扩展到函数的第一个参数(在您的示例中为“ node”),然后将其传递给xargs
并视为应执行的命令的一部分。也就是说,管道的最后一部分扩展为:
xargs -l1 echo node
......因此,当xargs
收到“ 18780”作为输入时,它将运行echo node 18780
,它当然会打印“ node 18780”。
解决方案:删除$1
,使命令仅为xargs -l1 echo
,因此,当xargs收到输入“ 18780”作为输入时,它将运行echo 18780
,仅显示“ 18780”。
这将解决问题,但是在此还可以进行大量简化。管道的许多元素都没有做任何有用的事情,或者正在相互交叉使用。
从管道中的最后一条命令xargs
开始。它接收PID,每行一个,然后每行打印一次。它根本没有做任何事情(无论如何我都可以看到),所以就别管它了。 (当然,除非您实际上要使用kill
而不是echo
-在这种情况下,请保留它。)
现在从头开始看看接下来的两个命令:
awk "{printf \"%s \",\$2}" | tr " " "\n"`
在这里,awk
在每个PID后面打印一个空格,然后tr
将这些空格变成换行符。为什么不awk
仅用换行符开始打印每个行?您甚至不需要printf
,只需使用print
,因为它会自动添加换行符。以单引号将脚本传递到awk
也更简单,因此您不必转义双引号,美元符号和(也许)反斜杠。因此,其中任何一个都可以工作:
awk "{printf \"%s\\n\",\$2}"
awk '{printf "%s\n",$2}'
awk '{print $2}'
自然,我推荐最后一个。
现在,关于awk
之前的命令:tr -s " " " "
。这种将空格的行“压缩”为单个空格,但这不是必需的,因为awk
将空格的行视为(单个)字段定界符。因此,再次省略该命令。
这时,我们进入以下管道:
ps aux | grep $1 | awk '{print $2}'
我还要在这里推荐两件事。首先,您应该(几乎)始终在外壳变量,参数等引用(例如$1
)周围加上双引号。因此,请改用grep "$1"
。
但是不要那样做,因为awk
完全可以搜索; grep
和 awk
都不需要。实际上,awk
可以更精确,仅搜索特定字段而不是整行。缺点是,这样做有点复杂,但是知道如何使awk
做更复杂的事情很有用。使awk
与shell变量或参数一起使用的最佳方法是使用其-v
选项创建具有相同值的awk变量,然后使用它。然后,您可以使用~
检查该变量的正则表达式是否匹配。像这样:
awk -v proc="$1" '$11 ~ proc {print $2}'
注意:我假设您要在可执行文件名称中搜索$1
,这就是系统上ps aux
的第11个字段。仅搜索该字段将使其无法匹配,例如用户名(杀死用户的所有进程,因为它们的名称包含某些程序名称是不礼貌的)。您实际上可能希望更加具体,例如尝试杀死node
也不会偶然杀死nodemon
;这将是使用更具体的搜索模式的问题。
所以,这是最终结果:
killProcess(){
ps aux | awk -v proc="$1" '$11 ~ proc {print $2}'
}
要真正终止进程,请在末尾添加xargs -l1 kill
。