bash脚本将输入参数与管道xargs参数连接起来

时间:2019-12-25 05:39:35

标签: bash

我试图执行我的脚本,但是$ 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参数能够删除它们,只有当我将其放在脚本下时才会发生,在命令行中它对我来说正常工作,因为我没有传递任何参数到脚本,它不会被串联。

1 个答案:

答案 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