防止 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
可以自己完成grep
和cut
的工作,因此即使您要坚持使用管道,也没有理由让它如此复杂。
即: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等命令组合)(转)