如何在Linux上使用xargs命令

需要将一些Linux命令串在一起,但其中一个命令不接受管道输入?xargs可以从一个命令获取输出并将其作为参数发送到另一个命令。

所有标准的Linux实用程序都有三个与之相关联的数据流。它们是标准输入流(Stdin)、标准输出流(Stdout)和标准错误流(Stderr)。

这些流与文本一起工作。我们使用文本向命令发送输入(Stdin),响应(Stdout)以文本形式写入终端窗口。错误消息也会以文本(Stderr)的形式写入终端窗口。

Linux和类Unix操作系统的一大特性是能够将一个命令的stdout输出通过管道传输到第二个命令的stdin输入。第一个命令并不关心它的输出是否不会进入终端窗口,第二个命令也不关心它的输入是否不是来自键盘。

尽管所有Linux命令都有三个标准流,但并非所有命令都接受另一个命令的stdout作为其stdin的输入。这意味着您不能通过管道输入到它们。

xargs是使用标准数据流构建执行管道的命令。通过使用xargs,我们可以使诸如echo、rm和mkdir之类的命令接受标准输入作为参数。

xargs命令

xargs将接受管道输入。它还可以接受来自文件的输入。xargs使用该输入作为我们告诉它使用的命令的参数。如果我们不告诉xargs使用特定命令,它将默认使用echo。

我们可以使用它来演示xargs如何始终生成单行输出,即使是从多行输入。

如果我们将-1(每行列出一个文件)选项与ls一起使用,我们将获得单列文件名。

ls -1 ./*.sh

这将列出当前目录中的shell脚本文件。

不出所料,我们得到了一个单独的专栏。如果我们用管道通过xargs,我们会得到什么?

ls -1 ./*.sh | xargs

输出以一个长文本流的形式写入终端窗口。

正是这种功能让我们将参数xargs馈送到其他命令中。

将xargs与wc一起使用

我们可以使用xargs轻松地让WC计算多个文件中的单词、字符和行。

ls *.page | xargs wc

事情是这样的:

ls列出*.page文件并将该列表传递给xargs。 xargs将文件名传递给wc。 WC会将文件名视为已收到的命令行参数。

每个文件的统计数据与总体合计一起显示。

使用带有确认的xargs

我们可以使用-p(交互式)选项让xargs提示我们确认我们是否乐于继续。

如果我们通过xargs传递一个文件名字符串给Touch,那么Touch将为我们创建文件。

echo 'one two three' | xargs -p touch

将显示要执行的命令,xargs等待我们通过键入“y”或“Y”、或“n”或“N”进行响应,然后按Enter键。

如果您只按Enter键,它将被视为“n”。只有当您键入“y”或“Y”时,才会执行该命令。

我们按“y”键,然后按Enter键。我们可以使用ls检查文件是否已创建。

ls one two three

将xargs与多个命令一起使用

通过使用-i命令(初始参数)选项,我们可以将多个命令与xargs一起使用。

此选项定义“替换字符串”。只要命令行中出现替换字符串的标记,就会插入提供给xargs的值。

让我们使用tree命令来查看当前目录中的子目录。-d(目录)选项导致树忽略文件,仅报告目录。

tree -d

只有一个名为“images”的子目录。

在名为“directories.txt”的文件中,我们有一些希望创建的目录的名称。我们可以用cat查看它的内容。

cat directories.txt

我们将使用它作为xargs的输入数据。我们要执行的命令是:

cat directories.txt | xargs -I % sh -c 'echo %; mkdir %'

这段代码如下所示:

cat directories.txt|:这会将directrories.txt文件的内容(所有新目录名)推送到xargs中。 xargs-i%:这定义了一个带有标记“%”的“替换字符串”。 sh-c:这将启动一个新的子shell。c(命令)告诉shell从命令行读取命令。 ‘Echo%;mkdir%’:每个“%”标记都将被由xargs传递的目录名替换。echo命令将打印目录名;mkdir命令将创建目录。

目录逐一列出。

我们可以再次使用TREE来验证目录是否已创建。

tree -d

将文件复制到多个位置

我们可以使用xargs使用单个命令将文件复制到多个位置。

我们将通过管道将两个目录的名称传递到xargs中,作为输入参数。我们将告诉xargs一次只将这些参数中的一个传递给它正在使用的命令。

在本例中,命令是cp。因此,效果是调用cp两次,每次都使用两个目录中的一个作为命令行参数。允许这种情况发生的xargs参数是-n(最大数量)选项。我们要把这件事定为一件。

我们还将-v(详细)选项与cp一起使用,以便它报告正在发生的事情。

echo ~/Backups/ ~/Documents/page-files/ | xargs -n 1 cp -v ./*.page

文件将复制到这两个目录,一次复制一个目录。CP报告每个文件复制操作,以便我们可以看到它们正在发生。

删除嵌套目录中的文件

如果文件名中包含空格和陌生字符-例如换行符-xargs将无法正确解释它们。我们可以通过使用-0(空终止符)选项来解决这个问题。这告诉xargs使用空字符作为文件名的最后分隔符。

在本例中,我们将使用find。Find有自己的选项来处理文件名中的空格和陌生字符。它是-print0(全名,空字符)选项。

find . -name "*.png" -type f -print0 | xargs -0 rm -v -rf "{}"

这段代码如下所示:

找到。-name“*.png”:find将从当前目录搜索“。”用于名称与“*.png”匹配且为文件(type-f)的对象。 -Print0:名称将以空字符结尾,并支持空格和陌生字符。 xargs-0:xargs还会认为文件名以空结尾,空格和陌生字符不会造成问题。 rm-v-rf“{}”:rm将非常详细,并报告正在发生的情况(-v)。它将是递归的(-r)并查看嵌套子目录,并且将在不提示(-f)的情况下删除文件。“{}”替换为每个文件名。

搜索所有子目录,并删除与搜索模式匹配的文件。

正在删除嵌套目录

假设我们想要删除一组嵌套子目录。树会让我们看到它们的。

tree -dfind . -name "level_one" -type d printo | xargs -o rm -v -rf "{}"

此命令将使用find递归地在当前目录中搜索。搜索目标是名为“LEVEL_ONE”的目录。所有目录名通过xargs传递到rm。

此命令与前一个命令之间唯一重要的变化是,搜索项是最顶层目录的名称,并且-type d告诉find查找目录,而不是文件。

每个目录的名称在删除时都会打印出来。我们可以向TREE查询:

tree -d

所有嵌套的子目录都将被删除。

删除除一种文件类型之外的所有文件

我们可以使用find、xargs和rm删除除要保留的一种类型之外的所有文件。这有点违反直觉,但是我们提供了我们想要保留的文件类型的名称,而不是我们想要删除的文件类型的名称。

-not选项告诉find返回与搜索模式不匹配的文件名。我们再次对xargs使用-i选项(初始参数)。这次我们定义的替换字符串令牌是“{}”。这将与我们之前生成的替换字符串令牌的行为完全相同,该令牌恰好是一个“%”。

find . -type f -not - name "*.sh" -print0 | xargs -0 -I {} rm -v {}

我们可以和ls核实一下。目录中只剩下与“*.sh”搜索模式匹配的文件。

ls -l

使用Xargs创建存档文件

我们可以使用find来搜索文件,并将它们传递给到tar的xargs,以创建一个归档文件。

我们将在当前目录中进行搜索。搜索模式是“*.page”,因此我们将查找“.page”文件。

find ./ - name "*.page" -type f -print0 | xargs -0 -tar -cvzf page_files.tar.gz

创建存档文件时,文件会按预期列出。

数据调解器

有时候,当你把东西堆放在一起的时候,你需要一些脚手架。xargs弥合了可以输出信息的命令和不能接收信息的命令之间的差距。

xargs和find都有大量的选项。我们鼓励您查看他们的手册页以了解更多信息。