我试图复制一堆文件下面的目录和一些文件有空格和单引号在他们的名字。当我尝试用xargs将find和grep串在一起时,我得到以下错误:
find .|grep "FooBar"|xargs -I{} cp "{}" ~/foo/bar
xargs: unterminated quote
对于更健壮地使用xargs有什么建议吗?
这是在Mac OS X 10.5.3 (Leopard)上使用BSD xargs。
我试图复制一堆文件下面的目录和一些文件有空格和单引号在他们的名字。当我尝试用xargs将find和grep串在一起时,我得到以下错误:
find .|grep "FooBar"|xargs -I{} cp "{}" ~/foo/bar
xargs: unterminated quote
对于更健壮地使用xargs有什么建议吗?
这是在Mac OS X 10.5.3 (Leopard)上使用BSD xargs。
当前回答
请注意,其他答案中讨论的大多数选项在不使用GNU实用程序的平台上都不是标准的(例如Solaris、AIX、HP-UX)。关于“标准”xargs行为,请参阅POSIX规范。
我还发现xargs的行为,即它至少运行一次命令,即使没有输入,这是一个麻烦。
我写了我自己的xargs (xargl)的私人版本来处理名称中的空格问题(只有换行符分开-尽管'find…-print0'和'xargs -0'的组合非常简洁,因为文件名不能包含ASCII NUL '\0'字符。我的xargl还没有完整到值得发布的程度——特别是因为GNU的工具至少和它一样好。
其他回答
如果你正在使用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上是否可用呢?
请注意,其他答案中讨论的大多数选项在不使用GNU实用程序的平台上都不是标准的(例如Solaris、AIX、HP-UX)。关于“标准”xargs行为,请参阅POSIX规范。
我还发现xargs的行为,即它至少运行一次命令,即使没有输入,这是一个麻烦。
我写了我自己的xargs (xargl)的私人版本来处理名称中的空格问题(只有换行符分开-尽管'find…-print0'和'xargs -0'的组合非常简洁,因为文件名不能包含ASCII NUL '\0'字符。我的xargl还没有完整到值得发布的程度——特别是因为GNU的工具至少和它一样好。
bill_starr的Perl版本不能很好地用于嵌入换行符(只处理空格)。对于那些没有GNU工具的Solaris,一个更完整的版本可能是(使用sed)…
find -type f | sed 's/./\\&/g' | xargs grep string_to_find
根据需要调整find和grep参数或其他命令,但sed将修复嵌入的换行符/空格/制表符。
只是不要使用xargs。这是一个简洁的程序,但当面对非平凡的情况时,它不太适合find。
这是一个可移植的(POSIX)解决方案,即不需要find, xargs或cp GNU特定的扩展:
find . -name "*FooBar*" -exec sh -c 'cp -- "$@" ~/foo/bar' sh {} +
注意结尾的+而不是更常见的;。
这个解决方案:
正确处理带有嵌入空格、换行符或任何外来字符的文件和目录。 适用于任何Unix和Linux系统,即使是那些没有提供GNU工具包的系统。 不使用xargs,这是一个很好的有用的程序,但需要太多的调整和非标准特性来正确处理查找输出。 也比公认的和大多数(如果不是全部的话)其他答案更有效(读得更快)。
还要注意,尽管在其他一些回复或评论中声明了什么,引用{}是无用的(除非您使用的是异国情调的fishshell)。
对于那些依赖命令,而不是find,例如ls:
find . | grep "FooBar" | tr \\n \\0 | xargs -0 -I{} cp "{}" ~/foo/bar