bash 管道时何时使用 xargs?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35589179/
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-09-18 14:17:51  来源:igfitidea点击:

When to use xargs when piping?

bashxargs

提问by Sara Hamad

I am new to bash and I am trying to understand the use of xargs, which is still not clear for me. For example:

我是 bash 的新手,我试图了解 的使用xargs,这对我来说仍然不清楚。例如:

history | grep ls

Here I am searching for the command lsin my history. In this command, I did not use xargsand it worked fine.

在这里,我正在ls我的历史记录中搜索命令。在这个命令中,我没有使用xargs,它运行良好。

find /etc - name "*.txt" | xargs ls -l

I this one, I had to use xargsbut I still can not understand the difference and I am not able to decide correctly when to use xargsand when not.

我这个,我不得不使用,xargs但我仍然无法理解其中的区别,我无法正确决定何时使用xargs,何时不使用。

采纳答案by miken32

To answer your question, xargscan be used when you need to take the output from one command and use it as an argument to another. In your first example, greptakes the data from standard input, rather than as an argument. So, xargsis not needed.

要回答您的问题,xargs可以在您需要从一个命令中获取输出并将其用作另一个命令的参数时使用。在您的第一个示例中,grep从标准输入中获取数据,而不是作为参数。所以,xargs是不需要的。

xargstakes data from standard input and executes a command. By default, the data is appended to the end of the command as an argument. It can be inserted anywhere however, using a placeholder for the input. The traditional placeholder is {}; using that, your example command might then be written as:

xargs从标准输入获取数据并执行命令。默认情况下,数据作为参数附加到命令的末尾。然而,它可以插入到任何地方,使用占位符作为输入。传统的占位符是{}; 使用它,您的示例命令可能会写为:

find /etc -name "*.txt" | xargs -I {} ls -l {}

If you have 3 text files in /etcyou'll get a full directory listing of each. Of course, you could just have easily written ls -l /etc/*.txtand saved the trouble.

如果您有 3 个文本文件,/etc您将获得每个文件的完整目录列表。当然,您可以轻松编写ls -l /etc/*.txt并省去麻烦。

Another example lets you rename those files, and requires the placeholder {}to be used twice.

另一个示例让您重命名这些文件,并要求{}使用两次占位符。

find /etc -name "*.txt" | xargs -I {} mv {} {}.bak

These are both bad examples, and will break as soon as you have a filename containing whitespace. You can work around that by telling findto separate filenames with a null character.

这些都是不好的例子,一旦你的文件名包含空格就会中断。您可以通过告诉find用空字符分隔文件名来解决这个问题。

find /etc -print0 -name "*.txt" | xargs -I {} -0 mv {} {}.bak

My personal opinion is that there are almost always alternatives to using xargs, and you will be better served by learning those.

我个人的观点是,几乎总是有使用 的替代方法xargs,学习这些方法会更好地为您服务。

回答by Walter A

Short answer: Avoid xargsfor now. Return to xargswhen you have written dozens or hundreds of scripts.

简短回答:暂时避免xargsxargs当您编写了数十个或数百个脚本时返回。

Commands can get their input from parameters (like rm bad_example) or can get the input from stdin(not just the y on the question after rm -i is_this_bad_too, but also read answer). Other commands like grepand sedwill look for parameters and when the parameters don't show the input, switch to the input.
Your grepexample works fine reading from stdin, nothing special needed.
Your lsneeds the output of find as a parameter. xargsis just one way to turn things around. Use man xargsfor more about xargs. Alternatives:

命令可以从参数(如rm bad_example)获取输入,也可以从stdin(不仅是 之后问题上的 y rm -i is_this_bad_too,还有read answer)获取输入。其他命令如grepsed将查找参数,当参数不显示输入时,切换到输入。
您的grep示例可以从标准输入正常读取,没有什么特别需要的。
ls需要将 find 的输出作为参数。xargs只是扭转局面的一种方式。用于man xargs了解更多关于 xargs 的信息。备择方案:

find /etc -name "*.txt" -exec ls -l {} \;
find /etc -name "*.txt" -ls
ls -l $(find /etc -name "*.txt" )
ls /etc/*.txt

First try to see which of this commands is best when you have a nasty filename with spaces.txtin /etc.

首先尝试查看a nasty filename with spaces.txt在 /etc 中有哪些命令是最好的。

回答by Nothing More

When you use piping without xargs, the actual data is fed into the next command. On the other hand, when using piping with xargs, the actual data is viewed as a parameter to the next command. To give a concrete example, say you have a folder with a.txtand b.txt. a.txtcontains just a single line 'hello world!', and b.txtis just empty.

当您使用不带xargs的管道时,实际数据将输入下一个命令。另一方面,当使用带有xargs的管道时,实际数据被视为下一个命令的参数。举一个具体的例子,假设你有一个文件夹a.txtb.txta.txt只包含一行' hello world! ',并且b.txt只是空的。

If you do

如果你这样做

ls | grep txt

you would end up getting the output:

你最终会得到输出:

a.txt
b.txt

Yet, if you do

然而,如果你这样做

ls | xargs grep txt

you would get nothing since neither file a.txt nor b.txt contains the word txt.

你什么也得不到,因为文件 a.txt 和 b.txt 都不包含单词txt

If the command is

如果命令是

ls | xargs grep hello

you would get:

你会得到:

hello world!

That's because with xargs, the two filenames given by lsare passed to grepas arguments, rather than the actual content.

那是因为 with xargs,由 给出的两个文件名作为参数ls传递给grep,而不是实际内容。

回答by Ole Tange

GNU Parallel can do the same as xargs, but does not have the broken and exploitable "features".

GNU Parallel 可以执行与 xargs 相同的操作,但没有损坏和可利用的“功能”。

You can learn GNU Parallel by looking at examples http://www.gnu.org/software/parallel/man.html#EXAMPLE:-Working-as-xargs--n1.-Argument-appendingand walking through the tutorial http://www.gnu.org/software/parallel/parallel_tutorial.html

您可以通过查看示例http://www.gnu.org/software/parallel/man.html#EXAMPLE:-Working-as-xargs--n1.-Argument-appending并浏览教程http: //www.gnu.org/software/parallel/parallel_tutorial.html

回答by Rany Albeg Wein

xargs(1) is dangerous (broken, exploitable, etc.) when reading non-NUL-delimited input.

xargs(1) 在读取非 NUL 分隔的 input时很危险(损坏、可利用等)。

If you're working with filenames, use find's -exec [command] {} + instead. If you can get NUL-delimited output, use xargs -0.

如果您正在处理文件名,请改用find's -exec [command] {} +。如果您可以获得以 NUL 分隔的输出,请使用xargs -0.