Linux 如何使用 xargs 复制名称中包含空格和引号的文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/143171/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 16:32:14  来源:igfitidea点击:

How can I use xargs to copy files that have spaces and quotes in their names?

linuxmacosunixcommand-linexargs

提问by Drew Stephens

I'm trying to copy a bunch of files below a directory and a number of the files have spaces and single-quotes in their names. When I try to string together findand grepwith xargs, I get the following error:

我正在尝试在目录下复制一堆文件,并且许多文件的名称中有空格和单引号。当我尝试将find和串在一起grepxargs,出现以下错误:

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

Any suggestions for a more robust usage of xargs?

对更强大地使用 xargs 有什么建议吗?

This is on Mac OS X 10.5.3(Leopard) with BSD xargs.

这是在带有 BSD 的Mac OS X 10.5.3(Leopard) 上xargs

采纳答案by godbyk

You can combine all of that into a single findcommand:

您可以将所有这些组合成一个find命令:

find . -iname "*foobar*" -exec cp -- "{}" ~/foo/bar \;

This will handle filenames and directories with spaces in them. You can use -nameto get case-sensitive results.

这将处理其中包含空格的文件名和目录。您可以使用-name来获取区分大小写的结果。

Note: The --flag passed to cpprevents it from processing files starting with -as options.

注意:--传递给的标志cp阻止它处理-以选项开头的文件。

回答by Chris Jester-Young

find . -print0 | grep --null 'FooBar' | xargs -0 ...

find . -print0 | grep --null 'FooBar' | xargs -0 ...

I don't know about whether grepsupports --null, nor whether xargssupports -0, on Leopard, but on GNU it's all good.

我不知道是否grep支持--null,是否也xargs支持-0,豹,但在GNU这一切都很好。

回答by Shannon Nelson

Look into using the --null commandline option for xargs with the -print0 option in find.

考虑在 find 中使用 xargs 的 --null 命令行选项和 -print0 选项。

回答by Tometzky

This is more efficient as it does not run "cp" multiple times:

这更有效,因为它不会多次运行“cp”:

find -name '*FooBar*' -print0 | xargs -0 cp -t ~/foo/bar

回答by Jonathan Leffler

Be aware that most of the options discussed in other answers are not standard on platforms that do not use the GNU utilities (Solaris, AIX, HP-UX, for instance). See the POSIXspecification for 'standard' xargs behaviour.

请注意,其他答案中讨论的大多数选项在不使用 GNU 实用程序(例如 Solaris、AIX、HP-UX)的平台上都不是标准的。有关“标准”xargs 行为,请参阅POSIX规范。

I also find the behaviour of xargs whereby it runs the command at least once, even with no input, to be a nuisance.

我还发现 xargs 的行为,即使没有输入,它也至少运行一次命令,这很麻烦。

I wrote my own private version of xargs (xargl) to deal with the problems of spaces in names (only newlines separate - though the 'find ... -print0' and 'xargs -0' combination is pretty neat given that file names cannot contain ASCII NUL '\0' characters. My xargl isn't as complete as it would need to be to be worth publishing - especially since GNU has facilities that are at least as good.

我编写了自己的 xargs (xargl) 私人版本来处理名称中的空格问题(只有换行符分开 - 尽管 'find ... -print0' 和 'xargs -0' 组合非常简洁,因为文件名不能包含 ASCII NUL '\0' 字符。我的 xargl 并不像值得发布的那样完整 - 特别是因为 GNU 具有至少同样好的设施。

回答by Jonathan Leffler

I have found that the following syntax works well for me.

我发现以下语法对我很有效。

find /usr/pcapps/ -mount -type f -size +1000000c | perl -lpe ' s{ }{\ }g ' | xargs ls -l | sort +4nr | head -200

In this example, I am looking for the largest 200 files over 1,000,000 bytes in the filesystem mounted at "/usr/pcapps".

在此示例中,我正在查找挂载在“/usr/pcapps”的文件系统中超过 1,000,000 字节的最大 200 个文件。

The Perl line-liner between "find" and "xargs" escapes/quotes each blank so "xargs" passes any filename with embedded blanks to "ls" as a single argument.

“find”和“xargs”之间的Perl line-liner转义/引用每个空格,因此“xargs”将任何带有嵌入空格的文件名作为单个参数传递给“ls”。

回答by Jonathan Leffler

bill_starr's Perl versionwon't work well for embedded newlines (only copes with spaces). For those on e.g. Solaris where you don't have the GNU tools, a more complete version might be (using sed)...

bill_starr 的 Perl 版本不适用于嵌入的换行符(仅处理空格)。对于那些在例如 Solaris 上没有 GNU 工具的人来说,更完整的版本可能是(使用 sed)...

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

adjust the find and grep arguments or other commands as you require, but the sed will fix your embedded newlines/spaces/tabs.

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

回答by Carl Yamamoto-Furst

I used Bill Star's answerslightly modified on Solaris:

我使用了Bill Star在 Solaris 上稍加修改的答案

find . -mtime +2 | perl -pe 's{^}{\"};s{$}{\"}' > ~/output.file

This will put quotes around each line. I didn't use the '-l' option although it probably would help.

这将在每一行周围加上引号。我没有使用 '-l' 选项,尽管它可能会有所帮助。

The file list I was going though might have '-', but not newlines. I haven't used the output file with any other commands as I want to review what was found before I just start massively deleting them via xargs.

我要去的文件列表虽然可能有“-”,但没有换行符。我没有将输出文件与任何其他命令一起使用,因为我想在开始通过 xargs 大量删除它们之前查看发现的内容。

回答by mavit

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

I believe that this will work reliably for any character except line-feed (and I suspect that if you've got line-feeds in your filenames, then you've got worse problems than this). It doesn't require GNU findutils, just Perl, so it should work pretty-much anywhere.

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

回答by oyouareatubeo

I ran into the same problem. Here's how I solved it:

我遇到了同样的问题。这是我解决它的方法:

find . -name '*FoooBar*' | sed 's/.*/"&"/' | xargs cp ~/foo/bar

I used sedto substitute each line of input with the same line, but surrounded by double quotes. From the sedman page, "...An ampersand (``&'') appearing in the replacement is replaced by the string matching the RE..." -- in this case, .*, the entire line.

我曾经sed用同一行替换每一行输入,但用双引号括起来。在sed手册页中,“ ...出现在替换中的与号 (``&'') 被与 RE... 匹配的字符串替换”——在这种情况下.*,是整行。

This solves the xargs: unterminated quoteerror.

这解决了xargs: unterminated quote错误。