浅谈 xargs 的几个妙用

一直以来,xargs 都被我用作是管道符的连接命令,比如 cat delete.txt|xargs rm -f,并且一般是在直接管道不可用的情况下,才会想起用 xargs 命令来分行处理。但是今天,在使用 xargs 进行文件批处理的时候,发现了很多 xargs 的小妙用。

替换字符串

xargs -I 将指定一个字符串 {},用于代替接受的字符串进行操作,类似于 find -exec{}

比如,有10个文件,想要将他们重命名为以 .txt 结尾,可以这么操作:

1
2
3
4
5
6
[asbuser@2B2C-test-DB1 tmp]$ ls
0 1 2 3 4 5 6 7 8 9
[asbuser@2B2C-test-DB1 tmp]$ ls|xargs -I {} mv {} {}.txt
[asbuser@2B2C-test-DB1 tmp]$ ls
0.txt 1.txt 2.txt 3.txt 4.txt 5.txt 6.txt 7.txt 8.txt 9.txt
[asbuser@2B2C-test-DB1 tmp]$

多行输入单行输出

xargs 虽然是分行处理工具,但其默认输出却是单行的:

1
2
3
4
5
6
7
8
[asbuser@2B2C-test-DB1 tmp]$ cat 0.txt 
123
456
779
000
[asbuser@2B2C-test-DB1 tmp]$ cat 0.txt|xargs
123 456 779 000
[asbuser@2B2C-test-DB1 tmp]$

单行输入多行输出

xargs -n 可指定输出时每行输出多少个参数:

1
2
3
4
5
6
[asbuser@2B2C-test-DB1 tmp]$ cat 1.txt
123 456 789 000
[asbuser@2B2C-test-DB1 tmp]$ cat 1.txt|xargs -n2
123 456
789 000
[asbuser@2B2C-test-DB1 tmp]$

xargs -d 可指定一个定界符,分割参数,和 cut -d 类似:

1
2
3
4
5
6
[asbuser@2B2C-test-DB1 tmp]$ cat 2.txt 
123x456x789x000
[asbuser@2B2C-test-DB1 tmp]$ cat 2.txt|xargs -dx
123 456 789 000

[asbuser@2B2C-test-DB1 tmp]$

-n-d 结合使用:

1
2
3
4
5
6
7
[asbuser@2B2C-test-DB1 tmp]$ cat 2.txt 
123x456x789x000
[asbuser@2B2C-test-DB1 tmp]$ cat 2.txt|xargs -dx -n2
123 456
789 000

[asbuser@2B2C-test-DB1 tmp]$

处理带空格的文件名

当文件名包含空格时,作字符分割往往会出错,比如:

1
2
3
4
5
6
7
8
9
10
11
[asbuser@2B2C-test-DB1 tmp]$ ls
0 0 0.txt 0.txt 1.txt 2.txt 3.txt 4.txt 5.txt 6.txt 7.txt 8.txt 9.txt
[asbuser@2B2C-test-DB1 tmp]$ ls|xargs -n2
0 0
0.txt 0.txt
1.txt 2.txt
3.txt 4.txt
5.txt 6.txt
7.txt 8.txt
9.txt
[asbuser@2B2C-test-DB1 tmp]$

上面这个命令,将 0 0 0.txt 这个文件名称也给分割了。

为了避免这种情况,我们需要加上 -0 参数,-0\0 作为定界符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[asbuser@2B2C-test-DB1 tmp]$ ls|xargs -n2
0 0
0.txt 0.txt
1.txt 2.txt
3.txt 4.txt
5.txt 6.txt
7.txt 8.txt
9.txt
[asbuser@2B2C-test-DB1 tmp]$ ls|xargs -0 -n2
0 0 0.txt
0.txt
1.txt
2.txt
3.txt
4.txt
5.txt
6.txt
7.txt
8.txt
9.txt

[asbuser@2B2C-test-DB1 tmp]$

对于此情况,官方也有特别说明:

1
2
3
4
5
6
7
8
9
10
find /tmp -name core -type f -print | xargs /bin/rm -f

Find files named core in or below the directory /tmp and delete them. Note that
this will work incorrectly if there are any filenames containing newlines or spaces.

find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f

Find files named core in or below the directory /tmp and delete them, processing
filenames in such a way that file or directory names containing spaces or newlines
are correctly handled.