如何告诉“xargs”忽略空的标准输出?

如何告诉“xargs”忽略空的标准输出?

如何更改此代码以免发出错误,换句话说,xargs如果 stdout 为空,则不执行之后的代码。

终端:

$ cat << EOF > dummy.sh
#! /usr/bin/env bash
[[ -f "\$1" ]] &&  echo "file=\$1" || { echo "error"; exit 1; } 
shift 
(( \$# == 0 )) || "\$0" "\$@" 
EOF
$ chmod +x dummy.sh
$ mkdir trash.later && touch trash.later/foo
$ find trash.later -type f | xargs -n 1 ./dummy.sh 
file=trash.later/foo
$ find trash.later -type f | grep 'bar' | xargs -n 1 ./dummy.sh 
error

答案1

不要xargs在 的输出上使用findxargs默认情况下,期望输入参数以没有命令输出的格式分隔,当然不是find。的输出find -print也不能可靠地进行后处理。

find使用sort-of-reliously 的唯一方法xargs是使用-print0-0非标准扩展(最初来自 GNU find/ xargs,但现在在许多其他实现中找到)。

GNUxargs还有一个-r/--no-run-if-empty扩展名,如果输入为空,则不运行该命令(某些xargs实现,例如 NetBSD 上的默认情况下会执行此操作)。

所以在这里,使用 GNU find//xargsgrep兼容的,你可以这样做:

find trash.later -type f -print0 |
  grep -z bar |
  xargs -r -0 -n 1 ./dummy.sh

但这与标准相比没有任何优势:

find trash.later -path '*bar*' -type f -exec ./dummy.sh {} ';'

(在其中-path '*bar*'查找bar文件路径中的任何位置,就像您grep bar尝试做的那样。替换为仅在文件名中-name '*bar*'查找(其路径的最后一个组成部分))。bar

更多相关内容请阅读:为什么循环查找的输出是不好的做法?


作为对您的问题的更一般的回答,对于xargs不支持-r/ 的实现--no-run-if-empty,解决方法是使用sh包装器。

代替:

... | xargs -n1 cmd

做:

... | xargs sh -c 'for file do cmd "$file"; done' sh

如果没有输入,它仍然会运行sh,但由于参数列表为空,循环中不会有传递,因此cmd不会运行。

另请参阅仅在输入非空时运行命令ifne的命令moreutils

... | ifne xargs -n1 cmd

但请注意,如果输入不为空而仅包含空行,ifne则会运行,xargsxargs仍会认为其输入没有参数,并且仍然在cmd没有参数的情况下运行一次(NetBSD 上除外)。

为了完整性

... | xargs -I {} cmd {}

cmd如果输入为空/空白,也不会运行。在这种情况下,将输入拆分为参数是不同的:删除前导空格,仍然处理引号(以xargs自己独特的方式),但除此之外,参数是整行而不是空格分隔的单词。

相关内容