我试图复制一堆文件下面的目录和一些文件有空格和单引号在他们的名字。当我尝试用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。
当前回答
我围绕“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上都很好。
我使用了Bill Star在Solaris上稍作修改的回答:
find . -mtime +2 | perl -pe 's{^}{\"};s{$}{\"}' > ~/output.file
这将在每行周围加上引号。我没有使用“-l”选项,尽管它可能会有所帮助。
我要去的文件列表可能有'-',但没有换行符。我没有使用输出文件与任何其他命令,因为我想回顾什么是发现之前,我只是开始大规模删除他们通过xargs。
框架挑战-你正在询问如何使用xargs。答案是:不使用xargs,因为不需要它。
user80168的注释描述了一种直接使用cp的方法,而不需要对每个文件调用cp:
find . -name '*FooBar*' -exec cp -t /tmp -- {} +
这很有效,因为:
cp -t标志允许在靠近cp开头的位置给出目标目录,而不是靠近结束的位置。来自男人cp:
- t,目标目录=目录 将所有SOURCE参数复制到DIRECTORY中
——标志告诉cp将后面的所有内容解释为文件名,而不是标志,因此以-或——开头的文件不会混淆cp;您仍然需要这样做,因为-/——字符由cp解释,而任何其他特殊字符由shell解释。 find -exec命令{}+变体本质上与xargs相同。从人类发现:
-exec command {} + This variant of the -exec action runs the specified command on the selected files, but the command line is built by appending each selected file name at the end; the total number of invoca‐ matched files. The command line is built in much the same way that xargs builds its command lines. Only one instance of `{}' is allowed within the command, and (when find is being invoked from a shell) it should be quoted (for example, '{}') to protect it from interpretation by shells. The command is executed in the starting directory. If any invocation returns a non-zero value as exit status, then find returns a non-zero exit status. If find encounters an error, this can sometimes cause an immedi‐ ate exit, so some pending commands may not be run at all. This variant of -exec always returns true.
通过直接在find中使用它,就避免了管道或shell调用的需要,这样您就不需要担心文件名中任何讨厌的字符。
你可能需要像这样grep Foobar目录:
find . -name "file.ext"| grep "FooBar" | xargs -i cp -p "{}" .
我也遇到了同样的问题。以下是我的解决方法:
find . -name '*FoooBar*' | sed 's/.*/"&"/' | xargs cp ~/foo/bar
我使用sed将每一行输入替换为同一行,但是用双引号括起来。在sed手册页中,“…替换中出现的&号('' & ")将被匹配RE…"的字符串替换。"——在本例中,.*表示整行。
这解决了xargs: unterminated quote错误。