我试图复制一堆文件下面的目录和一些文件有空格和单引号在他们的名字。当我尝试用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。
当前回答
这更有效,因为它不会多次运行“cp”:
find -name '*FooBar*' -print0 | xargs -0 cp -t ~/foo/bar
其他回答
如果系统上的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上测试
只是不要使用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
我围绕“xargs”创建了一个名为“xargsL”的小型便携式包装器脚本,该脚本可以解决大多数问题。
与xargs相反,xargsL接受每行一个路径名。路径名可以包含除换行符或NUL字节以外的任何字符。
在文件列表中不允许或不支持引用—您的文件名可能包含各种空格、反斜杠、反勾号、shell通配符等等—xargsL将把它们作为文字字符处理,不会造成任何损害。
作为一个额外的特性,如果没有输入,xargsL将不会运行一次命令!
注意区别:
$ true | xargs echo no data
no data
$ true | xargsL echo no data # No output
给xargsL的任何参数都将传递给xargs。
下面是"xargsL" POSIX shell脚本:
#! /bin/sh # Line-based version of "xargs" (one pathname per line which may contain any # amount of whitespace except for newlines) with the added bonus feature that # it will not execute the command if the input file is empty. # # Version 2018.76.3 # # Copyright (c) 2018 Guenther Brunthaler. All rights reserved. # # This script is free software. # Distribution is permitted under the terms of the GPLv3. set -e trap 'test $? = 0 || echo "$0 failed!" >& 2' 0 if IFS= read -r first then { printf '%s\n' "$first" cat } | sed 's/./\\&/g' | xargs ${1+"$@"} fi
将脚本放到$PATH中的某个目录中,不要忘记
$ chmod +x xargsL
那里的脚本使它可执行。
找到。-print0 | grep——null 'FooBar' | xargs -0…
我不知道grep是否支持-null,也不知道xargs是否支持-0,在Leopard上,但在GNU上都很好。