我怎样才能用xargs来复制名称中有空格和引号的文件呢?
我试图在一个目录下面复制一堆文件,其中一些文件的名称中有空格和单引号。 当我尝试串起来find
和grep
与xargs
,我得到以下错误:
find .|grep "FooBar"|xargs -I{} cp "{}" ~/foo/bar xargs: unterminated quote
任何build议更强大的使用xargs?
这是在MacOS 10.5.3与BSD xargs
。
您也可以将所有这些组合到一个查找命令中:
find . -iname "*foobar*" -exec cp "{}" ~/foo/bar \;
这将处理文件名和目录中的空格。 您可以使用-name来获得区分大小写的结果。
(这些命令行参数可以用于GNU查找;我不知道它们是否可用于BSD或OS X的查找。)
find . -print0 | grep --null 'FooBar' | xargs -0 ...
我不知道grep
是否支持 – 无论是xargs
在Leopard上支持-0
,还是在GNU上都是好的。
这样更有效,因为它不会多次运行“cp”:
find -name '*FooBar*' -print0 | xargs -0 cp -t ~/foo/bar
我遇到了同样的问题。 以下是我解决它的方法:
find . -name '*FoooBar*' | sed 's/.*/"&"/' | xargs cp ~/foo/bar
我用sed
用同一行replace每一行的input,但用双引号括起来。 从sed
手册页中,“ …replace中出现的&符(`&&')被replace为匹配RE的string… ” – 在这种情况下, .*
,整行。
这解决了xargs: unterminated quote
错误。
做最原始的海报所需要的最简单的方法是将分隔符从任何空格改为像这样的行尾字符:
find whatever ... | xargs -d "\n" cp -t /var/tmp
此方法适用于Mac OSx Lion 10.7.5
find . | grep FooBar | xargs -I{} cp {} ~/foo/bar
编辑:也只是testing你发布的确切语法。 这也在10.7.5上运行良好。
在find中使用带-print0选项的xargs的–null命令行选项。
这是一个便携式(POSIX)解决scheme,即不需要find
, xargs
或cp
GNU特定扩展的解决scheme:
find . -name "*FooBar*" -exec sh -c 'cp -- "$@" ~/foo/bar' sh {} +
它将正确地处理文件和目录与embedded式空格,换行符或任何,并且比接受的答案更高效(读取更快)。
我发现下面的语法适合我。
find /usr/pcapps/ -mount -type f -size +1000000c | perl -lpe ' s{ }{\\ }g ' | xargs ls -l | sort +4nr | head -200
在这个例子中,我正在寻找安装在“/ usr / pcapps”的文件系统中超过1,000,000字节的最大200个文件。
“find”和“xargs”之间的Perl换行符每个都是空格,所以“xargs”将带有空格的文件名作为单个parameter passing给“ls”。
Bill Starr星期五,2009年1月23日,美国东部时间下午5点40分
find | perl -lne 'print quotemeta' | xargs ls -d
我相信,除了换行符以外,任何字符都可以可靠地工作(而且我怀疑如果你的文件名中有换行符,那么你就会遇到比这更糟糕的问题)。 它不需要GNU findutils,只要Perl,所以它应该在任何地方工作。
对于那些依赖命令的人来说,除了find,比如ls
:
find . | grep "FooBar" | tr \\n \\0 | xargs -0 -I{} cp "{}" ~/foo/bar
请注意,其他答案中讨论的大多数选项在不使用GNU实用程序(例如Solaris,AIX和HP-UX)的平台上不是标准configuration。 有关“标准”xargs行为,请参阅POSIX规范。
我也发现了xargs的行为,即使没有任何input,它至less运行一次也是令人讨厌的。
我写了自己的xargs(xargl)专用版本来处理名称空间问题(只有换行符是分开的 – 虽然'find … -print0'和'xargs -0'组合非常整齐,因为文件名不能包含ASCII NUL'\ 0'字符。我的xargl并不像需要发布的那样完整 – 特别是因为GNU的function至less是一样的。
上面的Perl版本将不适用于embedded式换行符(仅适用于空格)。 对于那些例如你没有GNU工具的solaris,更完整的版本可能是(使用sed)…
find -type f | sed 's/./\\&/g' | xargs grep string_to_find
根据需要调整find和grep参数或其他命令,但sed将修复embedded的换行符/空格/制表符。
我在Solaris上稍微修改了Bill Star的回答:
find . -mtime +2 | perl -pe 's{^}{\"};s{$}{\"}' > ~/output.file
这将把每行的报价。 我没有使用'-l'选项,虽然它可能会帮助。
我正在去的文件列表可能有' – ',但不是换行符。 我没有使用任何其他命令的输出文件,因为我想查看之前我刚刚开始大规模删除它们通过xargs发现。
使用bash(而不是POSIX),你可以使用进程replace来获取variables中的当前行。 这使您可以使用引号来转义特殊字符:
while read line ; do cp "$line" ~/bar ; done < <(find . | grep foo)
我玩了一下,开始考虑修改xargs,并意识到对于我们在这里讨论的用例,python中的一个简单的重新实现是一个更好的主意。 一方面,对于整个事物来说,有80行代码意味着很容易找出正在发生的事情,如果需要不同的行为,可以用更less的时间将其转化为新的脚本,在某个地方像stackoverflow的答复。
用写的yargs(和python3安装),你可以键入
find .|grep "FooBar"|yargs -l 203 cp --after ~/foo/bar
一次复制203个文件。 (当然这里只是一个占位符,使用一个像203这样奇怪的数字表明这个数字没有其他意义。)
如果你真的想要更快的东西,而不需要python,把zargs和yargs作为原型,并用C ++或C重写。
对我来说,我试图做一些有点不同的事情。 我想将我的txt文件复制到我的tmp文件夹中。 txt文件名包含空格和撇号字符。 这在我的Mac上工作。
$ find . -type f -name '*.txt' | sed 's/'"'"'/\'"'"'/g' | sed 's/.*/"&"/' | xargs -I{} cp -v {} ./tmp/
对于愚蠢的非GNU版本的用户,如果文件名中有撇号,则Bill Starr的解决scheme将不起作用。 rjb1也有同样的问题,我认为,虽然我不能用testing复制它。 Carl Yamamoto-Furst的作品。
您可能需要像foobar目录grep:
find . -name "file.ext"| grep "FooBar" | xargs -i cp -p "{}" .
如果系统上的find和xarg版本不支持-print0
和-0
开关(例如AIX find和xargs),则可以使用以下非常可怕的代码:
find . -name "*foo*" | sed -e "s/'/\\\'/g" -e 's/"/\\"/g' -e 's/ /\\ /g' | xargs cp /your/dest
这里sed将负责转义xargs的空格和引号。
在AIX 5.3上testing
如果你正在使用bash,你可以通过mapfile
将stdout转换成一行数组,
find . | grep "FooBar" | (mapfile -t; cp "${MAPFILE[@]}" ~/foobar)
好处是:
- 它是内置的,所以速度更快。
- 一次执行所有文件名的命令,所以速度更快。
-
您可以将其他参数附加到文件名称。 对于
cp
,你也可以:find . -name '*FooBar*' -exec cp -t ~/foobar -- {} +
但是,有些命令没有这样的function。
缺点:
- 如果文件名太多,可能不能很好地扩展。 (限制?我不知道,但我已经testing了10MB的列表文件,其中包括10000+文件名没有问题,在Debian下)
那么谁知道bash是否在OS X上可用?