linux之xargs命令
前面文章专门介绍管道符时候提到过,一般情况下,处理文本的命令和工具均支持管道符,像rm、kill等命令则不支持管道符。但是有时候我们想要管道符支持这些命令,例如执行
ls *.sh | rm -rf 找出所有.sh类型的文件并且删除
ps -ef | grep "hello.sh" | awk '{print $2}' | kill 杀死包含"hello.sh"进程
实际上这些命令都是无法执行的,这时候就需要用到xargs命令与管道结合使用才能实现。
xargs的作用是接收管道符前面命令的输出进行处理后作为命令行参数传递给后续命令,而并不是作为标准输入传递给后续命令。
首先在这里再次解释一下命令行参数和标准输入的区别
- 命令行参数
命令行参数就是命令后面的参数
例如rm hello.sh
,rm是命令,hello.sh就是命令行参数
例如cat a.txt
, cat是命令,a.txt就是命令行参数 - 标准输入
管道符之前命令的输出结果(即打印在屏幕的文本)作为之后命令的标准输入
举个栗子:
cat a.txt | sort
这个命令是先查看a.txt文件然后对输出的内容进行排序,后面sort命令要处理的内容就是前面cat命令输出的内容,即cat命令的标准输出作为sort命令的标准输入,这个命令等价于sort a.txt
1.举个栗子来展示一下xargs的神奇作用:
有如下两个文件a.txt 和b.txt
[root@linuxforliuhj test]# ls *.txt
a.txt b.txt
[root@linuxforliuhj test]# cat a.txt
aaaa
dddd
cccc
bbbb
[root@linuxforliuhj test]# cat b.txt
1111
3333
4444
2222
[root@linuxforliuhj test]#
执行 ls *.txt | cat
[root@linuxforliuhj test]# ls *.txt | cat
a.txt
b.txt
[root@linuxforliuhj test]#
执行ls *.txt | xargs cat
[root@linuxforliuhj test]# ls *.txt | xargs cat
aaaa
dddd
cccc
bbbb
1111
3333
4444
2222
[root@linuxforliuhj test]#
从上面两个命令对比可以看到,第一个命令cat只是将ls命令打印到屏幕上的内容作为标准输入进行处理;第二个命令是将ls命令的输出进行处理后作为命令行参数执行,等价于 cat a.txt b.txt
2.xargs是如何对从管道接收的文本进行处理?
以空白字符(空格,tap,换行符均算空白字符)分隔从管道接收的文本,并且将分隔后文本均作为参数
有文件如下
[root@linuxforliuhj test]# cat x_test.sh
a.txt b.txt
c.txt d.txt
e.txt
[root@linuxforliuhj test]# cat a.txt
i am a
[root@linuxforliuhj test]# cat b.txt
i am b
[root@linuxforliuhj test]# cat c.txt
i am c
[root@linuxforliuhj test]# cat d.txt
i am d
[root@linuxforliuhj test]# cat e.txt
i am e
[root@linuxforliuhj test]#
执行cat x_test.sh | cat
[root@linuxforliuhj test]# cat x_test.sh | cat
a.txt b.txt
c.txt d.txt
e.txt
执行 cat x_test.sh |xargs cat
相当于执行cat a.txt b.txt c.txt d.txt e.txt
[root@linuxforliuhj test]# cat x_test.sh |xargs cat
i am a
i am b
i am c
i am d
i am e
我们对x_test.sh文件修改一下,新增两个文件file1和file2,但实际上这两个文件并不存在,再次执行cat x_test.sh |xargs cat
,等价于执行了cat a.txt b.txt c.txt d.txt e.txt file1 file2
[root@linuxforliuhj test]# cat x_test.sh
a.txt b.txt
c.txt d.txt
e.txt
file1 file2
[root@linuxforliuhj test]# cat x_test.sh |xargs cat
i am a
i am b
i am c
i am d
i am e
cat: file1: No such file or directory
cat: file2: No such file or directory
所以,xargs的作用就是将管道输出的文本进行处理以后作为命令行参数传递给后续命令,假如xargs将前面命令分隔成100个字段,那么这100个字段都将作为命令行参数传递给后续命令。
3.xargs常用选项
参数 | 解释 |
---|---|
-d | 指定分隔符 |
-p | 先打印即将执行的命令并询问是否执行 |
-n | 指定每次传输给后续命令的参数个数 |
【-d】默认是以空白字符分隔,可以指定字符分隔
[root@linuxforliuhj test]# cat test.sh
a.txt:b.txt
c.txt
[root@linuxforliuhj test]# cat test.sh | xargs cat
cat: a.txt:b.txt: No such file or directory
i am c
[root@linuxforliuhj test]# cat test.sh | xargs -d ':' cat
i am a
cat: b.txt
c.txt
: No such file or directory
[root@linuxforliuhj test]#
【-p】执行前先打印要执行的命令并询问,需要输入y继续执行
[root@linuxforliuhj test]# cat x_test.sh
a.txt b.txt
c.txt d.txt
e.txt
file1 file2
[root@linuxforliuhj test]# cat x_test.sh | xargs -p cat
cat a.txt b.txt c.txt d.txt e.txt file1 file2 ?...y
i am a
i am b
i am c
i am d
i am e
cat: file1: No such file or directory
cat: file2: No such file or directory
[root@linuxforliuhj test]#
加上-p参数会询问cat a.txt b.txt c.txt d.txt e.txt file1 file2 ?...
这个正是我们之前说的将分隔的文本作为后面命令的参数使用
【-n】每一次输入指定数量的参数给后续命令
cat x_test.sh | xargs -n 3 cat
等价于执行:
cat a.txt b.txt c.txt
cat d.txt e.txt file1
cat file2
4.对于rm、kill等本就不支持管道的命令,可以使用xargs结合管道一起使用
不加xargs执行后文件仍然没有被删除
[root@linuxforliuhj test]# ls *.txt
a.txt b.txt c.txt d.txt e.txt
[root@linuxforliuhj test]# ls *.txt | rm -rf
[root@linuxforliuhj test]# ls *.txt
a.txt b.txt c.txt d.txt e.txt
[root@linuxforliuhj test]#
使用xargs结合管道一起则可以删除文件
```bash
[root@linuxforliuhj test]# ls *.txt
a.txt b.txt c.txt d.txt e.txt
[root@linuxforliuhj test]# ls *.txt |xargs -p rm -rf
rm -rf a.txt b.txt c.txt d.txt e.txt ?...y
[root@linuxforliuhj test]# ls *.txt
ls: cannot access *.txt: No such file or directory
[root@linuxforliuhj test]#
同样,对于kill等命令依然实适用
[root@linuxforliuhj test]# ps -ef | grep 'test.sh' | grep -v 'grep'
root 15604 15185 0 22:26 pts/4 00:00:00 vim test.sh
[root@linuxforliuhj test]# ps -ef | grep 'test.sh' | grep -v 'grep'|awk '{print $2}' | xargs -p kill
kill 15604 ?...y
[root@linuxforliuhj test]# ps -ef | grep 'test.sh' | grep -v 'grep'
[root@linuxforliuhj test]#