简体   繁体   English

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

[英]bash script concatenates input arguments with pipe xargs arguments

I am trying to execute my script, but the $ 1 argument is concatenated with the arguments of the last pipe, resulting in the following我正在尝试执行我的脚本,但 $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

but I just want the list of pids, without the node argument to be able to delete them, that only happens when I put it under a script, in command line it works normally for me because I don't pass any arguments to the script and it doesn't get concatenated.但我只想要pids列表,没有节点参数能够删除它们,只有当我把它放在脚本下时才会发生,在命令行中它对我来说正常工作,因为我没有将任何参数传递给脚本它不会被连接起来。

The immediate problem is that you don't want the $1 at the end.直接的问题是你不想要最后的$1 In that context, $1 expands to the first argument to the function ("node", in your example), which then gets passed to xargs and treated as part of the command it should execute.在这种情况下, $1扩展为函数的第一个参数(在您的示例中为“node”),然后将其传递给xargs并被视为它应该执行的命令的一部分。 That is, the last part of the pipeline expands to:也就是说,管道的最后一部分扩展为:

xargs -l1 echo node

...so when xargs receives "18780" as input, it runs echo node 18780 , which of course prints "node 18780". ...所以当xargs接收“18780”作为输入时,它会运行echo node 18780 ,这当然会打印“node 18780”。

Solution: remove the $1 , making the command just xargs -l1 echo , so when xargs receives "18780" as input, it runs echo 18780 , which prints just "18780".解决方案:删除$1 ,使命令只是xargs -l1 echo ,所以当 xargs 接收“18780”作为输入时,它运行echo 18780echo 18780打印“18780”。

That'll fix it, but there's also a huge amount of simplification that can be done here.这会解决它,但也有大量的简化可以在这里完成。 Many elements of the pipe aren't doing anything useful, or are working at cross purposes with each other.管道的许多元素没有做任何有用的事情,或者彼此交叉工作。

Start with the last command in the pipe, xargs .从管道中的最后一个命令xargs It's taking in PIDs, one per line, and printing them one per line.它接收PID,每行一个,并每行打印一个。 It's not really doing anything at all (that I can see anyway), so just leave it off.它根本没有做任何事情(无论如何我都可以看到),所以就不要再管了。 (Unless, of course, you actually want to use kill instead of echo -- in that case, leave it on.) (当然,除非您真的想使用kill而不是echo —— 在这种情况下,请保持打开状态。)

Now look at the next two commands from the end:现在从最后看接下来的两个命令:

awk "{printf \"%s \",\$2}" | tr " " "\n"`

Here, awk is printing the PIDs with a space after each one, and then tr is turning the spaces into newlines.在这里, awk在每个 PID 后面打印一个空格,然后tr将空格转换为换行符。 Why not just have awk print each one with a newline to begin with?为什么不让awk以换行符开头打印每个? You don't even need printf for this, you can just use print since it automatically adds a newline.为此,您甚至不需要printf ,您可以只使用print因为它会自动添加换行符。 It's also simpler to pass the script to awk in single-quotes, so you don't have to escape the double-quotes, dollar sign, and (maybe) backslash.将脚本以单引号传递给awk也更简单,因此您不必转义双引号、美元符号和(可能)反斜杠。 So any of these would work:所以这些都可以工作:

awk "{printf \"%s\\n\",\$2}"
awk '{printf "%s\n",$2}'
awk '{print $2}'

Naturally, I recommend the last one.当然,我推荐最后一个。

Now, about the command before awk : tr -s " " " " .现在,关于awk之前的命令: tr -s " " " " This "squeezes" runs of spaces into single spaces, but that's not needed since awk treats runs of spaces as (single) field delimiters.这将空格运行“挤压”为单个空格,但这不是必需的,因为awk将空格运行视为(单个)字段分隔符。 So, again, leave that command out.所以,再一次,把这个命令排除在外。

At this point, we're down to the following pipeline:在这一点上,我们归结为以下管道:

ps aux | grep $1 | awk '{print $2}'

There are two more things I'd recommend here.这里还有两件事我要推荐。 First, you should (almost) always have double-quotes around shell variable, parameter, etc references like $1 .首先,您应该(几乎)始终在 shell 变量、参数等引用(如$1周围使用双引号。 So use grep "$1" instead.因此,请改用grep "$1"

But don't do that, because awk is perfectly capable of searching;但是不要那样做,因为awk完全有能力进行搜索; there's no need for both grep and awk .不需要grepawk In fact, awk can be much more precise, searching only a specific field instead of the whole line.事实上, awk可以更精确,只搜索特定字段而不是整行。 The downside is, it is a bit more complex to do, but knowing how to make awk do more complex things is useful.缺点是,它做起来有点复杂,但知道如何让awk做更复杂的事情是有用的。 The best way to let awk work with a shell variable or parameter is to use its -v option to create an awk variable with the same value, and use that.awk与 shell 变量或参数一起工作的最好方法是使用它的-v选项来创建一个具有相同值的 awk 变量,然后使用它。 You can then use the ~ to check for a regex match to the variable.然后,您可以使用~来检查与变量的正则表达式匹配。 Something like this:像这样的东西:

awk -v proc="$1" '$11 ~ proc {print $2}'

Note: I'm assuming you want to search for $1 in the executable name, and that that's the 11th field of ps aux on your system.注意:我假设您想在可执行文件名称中搜索$1 ,这是您系统上ps aux的第 11 个字段。 Searching that field only will keep it from matching in eg the username (killing all of a user's processes because their name contains some program name isn't polite).仅搜索该字段将使其不匹配例如用户名(杀死用户的所有进程,因为他们的名称包含一些程序名称是不礼貌的)。 You might actually want to be even more specific, so that eg trying to kill node doesn't accidentally kill nodemon as well;您实际上可能想要更具体,以便例如尝试杀死node也不会意外杀死nodemon that'll be a matter of using more specific search patterns.这将是使用更具体的搜索模式的问题。

So, here's the final result:所以,这是最终的结果:

killProcess(){
    ps aux | awk -v proc="$1" '$11 ~ proc {print $2}'
}

To actually kill the processes, add back xargs -l1 kill at the end.要真正xargs -l1 kill进程,请在最后添加xargs -l1 kill

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM