如何在Linux上使用xargs命令
需要将一些Linux命令串在一起,但是其中一个不接受管道输入吗? xargs可以将一个命令的输出作为参数发送给另一个命令。
所有标准Linux实用程序都有三个与之关联的数据流。它们是标准输入流(stdin),标准输出流(stdout)和标准错误流(stderr)。
这些流使用文本。我们使用文本将输入(stdin)发送到命令,然后将响应(stdout)作为文本写入终端窗口。错误消息也以文本(stderr)的形式写入终端窗口。
Linux和类Unix操作系统的一大功能是能够将标准输出从一个命令传递到第二个命令的stdin输入。第一个命令不在乎其输出不会进入终端窗口,第二个命令不在乎其输入不是来自键盘。
尽管所有Linux命令都具有三个标准流,但是并非所有命令都接受另一个命令的stdout作为其stdin的输入。这意味着我们无法通过管道将输入传递给他们。
xargs是用于使用标准数据流构建执行管道的命令。通过使用xargs,我们可以使诸如echo,rm和mkdir之类的命令接受标准输入作为参数。
xargs命令
xargs将接受管道输入。它还可以接受来自文件的输入。 xargs
使用该输入作为我们告诉它使用的命令的参数。如果我们不告诉xargs
使用特定命令,它将默认使用echo
。
我们可以用它来演示xargs将如何始终生成单行输出,即使是多行输入也是如此。
如果我们在ls
中使用-1
(每行列出一个文件)选项,则会得到一列文件名。
ls -1 ./*.sh
这列出了当前目录中的Shell脚本文件。
我们得到了预期的单列。如果我们通过xargs
传递它,我们会得到什么?
ls -1 ./*.sh | xargs
输出将作为一长串文本写入终端窗口。
正是这种能力使xargs将参数输入其他命令。
在wc中使用xargs
我们可以使用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忽略文件,只报告目录。
tree -d
有一个名为images的子目录。
在名为directorys.txt的文件中,我们具有要创建的某些目录的名称。我们可以使用cat
查看其内容。
cat directories.txt
我们将使用它作为xargs的输入数据。我们要执行的命令是:
cat directories.txt | xargs -I % sh -c 'echo %; mkdir %'
像这样分解:
cat directory.txt |:将directrories.txt文件的内容(所有新的目录名称)推送到xargs中。
xargs -I%:这定义了带有标记%的替换字符串。
sh -c:这将启动一个新的子shell。 -c(命令)告诉shell程序从命令行读取命令。
回声%; mkdir%':每个%标记都将由
xargs
传递的目录名称替换。echo
命令将打印目录名称; mkdir命令将创建目录。
目录被一一列出。
我们可以再次使用tree
来验证目录已经创建。
tree -d
将文件复制到多个位置
我们可以使用xargs
允许我们通过一个命令将文件复制到多个位置。
我们将把两个目录的名称作为输入参数传递到xargs
中。我们将告诉xargs
一次仅将这些参数之一传递给正在使用的命令。
在这种情况下,命令是" cp"。因此,效果是两次调用" cp",每次都使用两个目录之一作为命令行参数。允许这种情况发生的xargs参数是-n(最大数量)选项。我们将其设置为1.
我们还将-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匹配的对象(文件为-f型)。-print0:名称将以空字符结尾,并且将保留空格和奇怪字符。
xargs -0:xargs还将考虑文件名以null终止,并且空格和奇怪字符不会引起问题。
rm -v -rf {}:rm将会很冗长,并报告正在发生的事情(
-v
)。它将是递归(-r)并浏览嵌套的子目录,并且将删除文件而不提示(-f
)。 {}被每个文件名替换。
搜索所有子目录,并删除与搜索模式匹配的文件。
删除嵌套目录
假设我们要删除一组嵌套的子目录。树将让我们看到它们。
tree -d
find . -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"来搜索文件,并将它们通过" xargs"传递到" tar",以创建一个存档文件。
我们将在当前目录中搜索。搜索模式为* .page,因此我们将查找.page文件。
find ./ - name "*.page" -type f -print0 | xargs -0 -tar -cvzf page_files.tar.gz
创建存档文件后,文件将按预期列出。