防止 POSIX xargs 尝试运行空命令

Posted

技术标签:

【中文标题】防止 POSIX xargs 尝试运行空命令【英文标题】:Preventing POSIX xargs from attempting to run an empty command 【发布时间】:2016-03-30 03:53:19 【问题描述】:

我不太擅长 bash,但我正在尝试创建一个脚本来杀死一些 java 进程:

/usr/ucb/ps -auxww    \
  | grep 'XUnit'      \
  | grep -v 'grep'    \
  | cut -c -2000      \
  | awk 'print $2;' \
  | xargs kill

这里使用cut 是因为awk 可能会因行太长而失败(请参阅POSIX specification for awk 中的LINE_MAX 限制)。

当没有此类进程时会出现问题 - xargs 尝试不带参数运行 kill,从而导致错误。

我的 xargs 不接受 -r--no-run-if-empty 参数,正如对 a related question that doesn't specify POSIX compliance 的回答中所建议的那样。

【问题讨论】:

这里已经回答了:http://***.com/questions/8296710/ignore-empty-result-for-xargs 顺便说一句——如果你有pkill,你最好在单个命令中使用它来执行此操作,而不是尝试通过巨大的管道过滤ps 输出。此外,awk 可以自己完成grepcut 的工作,因此即使您要坚持使用管道,也没有理由让它如此复杂。 即:ps auxww | awk '(/XUnit/ && ! /awk/) print $2 '。但是,如上所述,最佳做法是根本不使用ps 嗯。阅读awk 的 POSIX 规范, 允许受制于LINE_MAX,通常为 2k。刚刚在那里学到了一些新东西——虽然我很好奇你使用的哪个实现实际上强制了这个限制。 @BenjaminW.,是的!我认为 POSIXly 简约的方法是ps -e -o pid= -o args= | awk '/[X]Unit/ print $1 '。如果您担心该限制,可以在 awk 之前抛出cut -c -$(getconf LINE_MAX) 【参考方案1】:

是的,通常情况下,xargs-r 选项,请参阅:

https://unix.stackexchange.com/questions/521595/if-there-is-empty-stdin-or-whatever-tell-xargs-not-to-care/521599#521599

否则你可以创建一个 bash 函数并在 xargs 之前放入管道:

handle_empty()
  while read line; do
    if test -z "$line"; then
        echo 'There was an empty line, exiting.' > /dev/stderr
        exit 0;
    fi
    echo "$line"
  done;


export -f handle_empty;

并像这样使用它:

docker volume ls -qf dangling=true | handle_empty | xargs docker volume rm 

有关更多信息,请参阅: https://gist.github.com/ORESoftware/bb8f97354ff38ee4a0a1dd1589af571a

【讨论】:

从问题的最后一行开始:我的 xargs 不接受 -r--no-run-if-empty args,正如对未指定 POSIX 合规性的相关问题的回答中所建议的那样。 同样,由于他们指定了严格的 POSIX 合规性,导出的函数也被淘汰了。 我不确定handle_empty 是否真的能满足您的需求。管道的所有部分同时运行——handle_empty 函数退出并不意味着xargs 不运行(或阻止xargs 在没有输入的情况下被调用;就此而言,如果没有输入,while read 循环将永远不会首先输入),它只是确保 xargs 看不到任何内容过去输入中的第一个空白行。【参考方案2】:

具体解决手头的问题,忽略手头的方法实际上是否是杀死进程的适当方法:

xargs sh -c '[ $# -gt 0 ] && exec "$0" "$@"' kill

这种方法让xargs 启动一个shell,它查看其参数列表的长度(如果只传递kill,则它将为0,因为-c 'script' 后面的参数以$0 开头,不包含在$#计数);该 shell 仅在给出至少一个参数时才运行给出的命令。

【讨论】:

为什么不在管道中加入handle_empty 函数呢?如果有一个空参数,则以 0 退出并回显 'there was a blank line'... 参见:gist.github.com/ORESoftware/bb8f97354ff38ee4a0a1dd1589af571a 或使用 -r 选项 - unix.stackexchange.com/questions/521595/… -r 不可移植-正如您链接的答案所示。导出的函数也不能移植到非 bash shell。 OP 很清楚,这个问题是专门要求一个可以在 POSIX 基线平台上运行的解决方案(并且我们已经有很多几乎没有这种要求的重复项)。 FWIW,我觉得 POSIX xargs 的这种行为方式非常有趣——甚至很危险。 @TorstenBronger,...老实说,缺少一些 -r 等价物可能是 POSIX xargs 的设计缺陷中最不危险的;它比类似 shell(但不是完全兼容 shell)的输入解析或允许实现执行子字符串扩展(因此鼓励 xargs -I sh -c '......' 使用模式与伴随的 shell 注入风险)要少得多。

以上是关于防止 POSIX xargs 尝试运行空命令的主要内容,如果未能解决你的问题,请参考以下文章

linux xargs命令一(与find ls等命令组合)(转)

如何在 xargs 命令中使用 &>>?

sbt 命令抛出空指针异常

PowerShell 中的 xargs 等价物是啥?

使用 ScriptBlock 调用命令在本地服务器上工作 - 远程结果集为空

xargs在shell的执行不能为空需要先判断