我试图复制一堆文件下面的目录和一些文件有空格和单引号在他们的名字。当我尝试用xargs将find和grep串在一起时,我得到以下错误:

find .|grep "FooBar"|xargs -I{} cp "{}" ~/foo/bar
xargs: unterminated quote

对于更健壮地使用xargs有什么建议吗?

这是在Mac OS X 10.5.3 (Leopard)上使用BSD xargs。


当前回答

使用Bash(而不是POSIX),您可以使用进程替换来获取变量中的当前行。这允许你使用引号转义特殊字符:

while read line ; do cp "$line" ~/bar ; done < <(find . | grep foo)

其他回答

find | perl -lne 'print quotemeta' | xargs ls -d

我相信这对于除换行以外的任何字符都是可靠的(并且我怀疑如果您的文件名中有换行,那么您将遇到比这更糟糕的问题)。它不需要GNU findutils,只需要Perl,所以它应该可以在任何地方工作。

对我来说,我想做一些不一样的事情。我想复制我的txt文件到我的tmp文件夹。txt文件包含空格和撇号。这在我的Mac上很管用。

$ find . -type f -name '*.txt' | sed 's/'"'"'/\'"'"'/g' | sed 's/.*/"&"/'  | xargs -I{} cp -v {} ./tmp/

如果你正在使用Bash,你可以通过mapfile将stdout转换为一个行数组:

find . | grep "FooBar" | (mapfile -t; cp "${MAPFILE[@]}" ~/foobar)

好处是:

它是内置的,所以更快。 一次执行所有文件名的命令,因此速度更快。 您可以将其他参数附加到文件名。对于cp,您还可以: 找到。-name '*FooBar*' -exec cp -t ~/ FooBar——{}+ 但是,有些命令不具备这样的特性。

的缺点:

如果文件名太多,可能伸缩性不好。(极限?我不知道,但我已经测试了10 MB的列表文件,其中包括10000多个文件名没有问题,在Debian下)

嗯…谁知道Bash在OS X上是否可用呢?

bill_starr的Perl版本不能很好地用于嵌入换行符(只处理空格)。对于那些没有GNU工具的Solaris,一个更完整的版本可能是(使用sed)…

find -type f | sed 's/./\\&/g' | xargs grep string_to_find

根据需要调整find和grep参数或其他命令,但sed将修复嵌入的换行符/空格/制表符。

找到。-print0 | grep——null 'FooBar' | xargs -0…

我不知道grep是否支持-null,也不知道xargs是否支持-0,在Leopard上,但在GNU上都很好。