如何更改此代码以免发出错误,换句话说,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
在 的输出上使用find
。xargs
默认情况下,期望输入参数以没有命令输出的格式分隔,当然不是find
。的输出find -print
也不能可靠地进行后处理。
find
使用sort-of-reliously 的唯一方法xargs
是使用-print0
和-0
非标准扩展(最初来自 GNU find
/ xargs
,但现在在许多其他实现中找到)。
GNUxargs
还有一个-r
/--no-run-if-empty
扩展名,如果输入为空,则不运行该命令(某些xargs
实现,例如 NetBSD 上的默认情况下会执行此操作)。
所以在这里,使用 GNU find
//xargs
或grep
兼容的,你可以这样做:
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
则会运行,xargs
但xargs
仍会认为其输入没有参数,并且仍然在cmd
没有参数的情况下运行一次(NetBSD 上除外)。
为了完整性
... | xargs -I {} cmd {}
cmd
如果输入为空/空白,也不会运行。在这种情况下,将输入拆分为参数是不同的:删除前导空格,仍然处理引号(以xargs
自己独特的方式),但除此之外,参数是整行而不是空格分隔的单词。