Linux——关于xargs命令的使用
前言
xargs命令在我们需要批量执行命令、复杂命令的参数传递时特别有用,下文就来介绍一下这个命令的用法吧
一、前置知识点
xargs
命令和标准输入有着一定的关系,在介绍这个命令之前我们不妨先了解标准输入、标准输出和错误输出分别是什么?
-
标准输入(stdin):通常用于向程序提供输入数据。
在命令行中,如果没有重定向,标准输入默认来自键盘。
可以通过管道(pipe)或重定向操作将文件或其他命令的输出作为标准输入。 -
标准输出(stdout):用于程序输出结果或信息。
在命令行中,如果没有重定向,标准输出默认显示在终端上。
可以通过管道将标准输出作为另一个命令的输入,或通过重定向操作将输出保存到文件中。 -
标准错误输出(stderr):用于程序输出错误信息或警告。
这允许程序将正常输出和错误信息分开,使得错误信息更容易被识别和处理。
在命令行中,标准错误输出默认也显示在终端上,但可以单独重定向到文件或其他命令。 -
文件描述符:这三个流都具有文件描述符(file descriptor):
标准输入的文件描述符是0。
标准输出的文件描述符是1。
标准错误输出的文件描述符是2。 -
管道符
管道命令(|)。管道命令的作用,是将左侧命令的标准输出转换为标准输入,提供给右侧命令作为参数。
二、 xargs
命令存在的作用
假设现在存在文件test.txt
,文件内容如下:
aa
bb
cc
我们执行cat test.txt | grep aa
,可以发现命令可以正常执行成功,这说明grep是支持标准输入作为入参的
如果我们执行cat test.txt | echo
命令会发现,test.txt
的内容并没有被打印出来,这是因为在Linux系统中,部分命令时不接受标准输入作为入参的
对于这类不支持标准输入作为入参的命令,linux提供了xargs命令来帮助我们进行桥接,或者说将标准输入转为命令行参数
三、使用键盘输入作为标准输入使用xargs
命令
xargs
命令支持我们单独执行,默认情况下xargs
相当于是xargs echo
,当我们输出xargs
时,控制台将会开始监听你的键盘输入,按ctrl + d
打印最终的结果。
我们还可以结合其他命令来使用
$ xargs find -name
"*.txt"
./foo.txt
./hello.txt
上面的例子输入xargs find -name
以后,命令行会等待用户输入所要搜索的文件。用户输入"*.txt",表示搜索当前目录下的所有 TXT 文件,然后按下Ctrl+d
,表示输入结束。这时就相当执行find -name *.txt
。
四、不同参数的使用
(一)使用-d
参数修改分隔符
默认情况下,xargs
命令将换行符和空格作为分隔符,把标准输入分解成一个个命令行参数。
例如下图中的案例
使用换行符作为分隔符
使用换行符作为分隔符使用空格作为分隔符
使用空格作为分隔符需要注意的是,如果同时存在换行符或者空格,那么
xargs
命令会基于这两种方式一起切割
如果标准输入不是以“空格”或者“换行符”进行分隔的话,我们可以通过-d
参数手动指定分隔符,具体可以看下面的案例
使用&
作为标准换行符
echo -n "aa&bb&cc" | xargs -d "&" mkdir
(二)使用-p
参数,-t
参数打印最终执行的命令
由于xargs
命令做了一层标准输入转入参的功能,所以有时候我们不能很方便的知道最终执行的命令是什么,这其实也是有一点点小小的风险,不过xargs
其实也是支持我们对最终的命令执行打印操作的。
-
image.png-p
参数打印出要执行的命令,询问用户是否要执行。
确认的话,输入大小写的y
都可以。取消的话,输入n就行(输入其他非y的内容也可以)
-
image.png-t
参数则是打印出最终要执行的命令,然后直接执行,不需要用户确认。
(三)使用-I
参数,定义参数名用于多次使用
从上文的使用中我们不难发现,对于一个标准输入,xargs
命令只能把它转换为入参用1次,但有时候我们需要重复用到这个入参,这个时候我们就可以使用-I
参数来完成我们的操作。
譬如当前目录中存在aa1
、aa2
、aa3
三个文件,我们希望把这些aa
开头的文件统一加上.txt
后缀,我们可以使用ls | grep aa | xargs -I fileName -t mv fileName fileName.txt
命令来完成操作。(这里的-t
参数只是为了打印,可以不加)
我们简单分析一下这条命令吧,ls
命令打印当前目录下的文件,grep aa
过滤出符合重命名条件的文件,xargs -I fileName
命令将得到的入参设了一个临时的变量名fileName,mv fileName fileName.txt
这里就是使用前面定义的fileName变量名
关于变量名的定义,比较通用的做法是把入参定义为
{}
,原因是使用 {} 作为占位符简洁明了,它直观地表示了这是一个将要被替换的位置。也就是说上面那条命令可以改写为ls | grep aa | xargs -I {} -t mv {} {}.txt
(四)使用-L
参数定义多少行作为一个命令行参数
假设我们现在有一个dirName
文件,文件内容是
aa1
bb1
cc1
我们希望根据这个文件里面的内容来作为目录名进行文件创建,那么我们执行cat dirName | xargs -p mkdir
命令,可以看到其实最终执行的命令是只有一条,就是mkdir aa1 bb1 cc1
。执行肯定是没有问题的,虽然xargs
命令一股脑把所有参数都传了过去,但因为mkdir
命令天然支持同时传入多个目录名来进行目录创建,所以命令在执行上也没有问题
但实际上,有些命令是不支持同时传入多个参数的,或者是一些命令支持批量操作的入参数量有限制,比如说
find
命令就不支持同时传入多个参数。这个时候就会要求我们把三个参数分成三次传入,也就是说命令会执行3次image.png
这时我们就可以传入
-L 1
来让每行作为1个命令行参数(也就是说这个命令每次执行至多接受1行的参数)image.png
(五)使用-n
参数定义多少项作为一个命令行参数
这个命令是基于有时候输入流不一定是每行只有一个参数的前提下出现的,我们在前文中提到了默认情况下xargs
命令会基于空格和换行符进行参数的分割,但是有时候由于一行之中可能又会切割出多个参数出来,所以直接用-L
可能不太准确。可以直接选择-n
参数来确定每次以多少个参数作为一个命令行参数。
比如说现在切分完成后一共得到了40个参数,我希望每次执行命令的时候依次传入2个参数,就可以使用-n 2
来实现。具体看案例:
我们希望把xargs
切分后的参数,每次只传1个参数到命令行中,来实现批量查询,就可以用cat dirName | xargs -n 1 -t find ./ -name
(-t
参数可以省略)
(六)使用--max-procs
参数进行多进程执行
xargs
默认只用一个进程执行命令。如果命令要执行多次,必须等上一次执行完,才能执行下一次。
--max-procs
参数指定同时用多少个进程并行执行命令。--max-procs 2
表示同时最多使用两个进程,--max-procs 0
表示不限制进程数。
比如删除当前目录下的所有文件:ls | xargs -n 1 -t --max-procs 2 rm -rf
小结
总的来说,xargs
命令可以帮助我们实现一些很酷很便捷的脚本操作,掌握这个命令会让工作简单不少。
一些常用的命令
删除当前目录内名称不包含fileName
的所有文件
find -type f . ! -name fileName* | xargs -n 1 -t rm -rf
参考文章
xargs 命令教程 https://ruanyifeng.com/blog/2019/08/xargs-tutorial.html