Linux常用命令--xargs

耗尽温柔 提交于 2020-02-29 02:13:22

我们可以用管道将一个命令的stdout(标准输出)重定向到另一个命令的stdin(标准输入),如:

$ cat foo.txt | grep "test"

解析:查看foo.txt文件并打印出含有test的行。

但是有些命令只能以命令行参数的形式接受数据,而无法通过stdin接受数据流。在这种情况下,我们没法用管道来提供哪些只有通过命令行参数才能提供的数据。

那现在就该xargs上场了,它擅长将标准输入数据转换成命令行参数。

预备知识:

xargs命令应该紧跟在管道操作符之后,以标准输入作为主要的源数据流,它使用stdin并通过提供命令行参数来执行其他命令。xargs命令把从stdin接收到的数据重新格式化,再将其作为参数提供给其他命令。

一、将多行输入转换成单行输出

$ cat foo.txt  #  样例文件
1 2 3 3 4 5
7 8 9 10
11 12

$ cat foo.txt | xargs
1 2 3 4 5 6 7 8 9 10 11 12

二、 将单行输入转换为多行输出

$ cat foo.txt | xargs -n 3
1 2 3
4 5 6
7 8 9
10 11 12

解析:指定每行最大的参数数量n,将任何来自stdin的文本划分成多行,每行n个参数。

xargs默认的定界符是空格,我们自己可以来设置定界符,用-d选项为输入指定一个定制的定界符。

$ echo "splitXsplitXsplitXsplit" | xargs -d X
split split split split

结合-n选项,我们可以将输入划分成多行,每行包含两个参数。

$ echo "splitXsplitXsplitXsplit" | xargs -d X -n 2
split split
split split

三、如何将参数传递给命令 读取stdin(标准输入),将格式化参数传递给命令

编写一个小型的echo来更好的理解用xargs提供命令行参数的方法:

#!/bin/bash
#filename: cecho.sh

echo $@  "#"

当参数传递给cecho.sh后,它将会把这些参数打印出来,并以# 字符结尾

$ ./eceho.sh arg1 arg2
arg1 arg2 #

那么,我们现在想把这个命令执行多次, 每次使用一个参数,难道我们只能一遍一遍的执行?现在,我们有一个名为args.txt的参数列表文件,内容为:

arg1
arg2
arg3

我们来看下面的代码

$ cat args.txt | xargs -n 1 ./cecho.sh
arg1 #
arg2 #
arg3 #

每次执行需要X个参数的命令时,使用:

$ cat args.txt | xargs -n 2 ./cecho.sh
arg1 arg2 #
arg3 #

但是有些时候,我们需要一些不变的参数,看下面这种命令格式:

$ ./cecho -p arg1 -1

在上面的命令执行过程中,arg1 是唯一可变的参数,其余部分都保持不变,我们可以从文件(argx.txt)中读取参数,按照下面的方式提供给命令:

./cecho -p arg1 -1
./cecho -p arg2 -1
./cecho -p arg3 -1

xargs有个一个-I(大写的i)的选项,可以提供上面这种形式的命令执行序列。我们用-I指定替换字符串,这个字符串在xargs扩展(传递给命令)时会被替换掉。如果将-I与xargs结合使用,对于每一个参数,命令都会被执行一次。

$ cat args.txt | xargs -I {} ./cecho -p {} -1

-p arg1 -1 #

-p arg2 -1 # 

-p arg3 -1 #

-I {}指定了替换字符串。对于每一个命令参数,字符串{}都会被从stdin读取到的参数所替换掉。使用-I的时候,命令会以循环的方式执行。如果有3个参数,那个命令就会被执行3次。在每一次执行的时候{}都会被替换为相应的参数。

xargs经常会与find一起使用,不过人们通常都会以一种错误的方式去使用它们。

$ find . type -f -name "*.txt" -print | xargs rm -f {} \;

我们没法预测find命令输出的结果的定界符是什么('\n'或' ')。很多文件都有可能包含空格符(' '),因此xargs很可能会误认为它们是定界符(例如:hell text.txt会被xargs理解为hello和text.txt两个文件)。

只要我们把find的输出作为xargs的输入,就必须将-print0与find结合使用,以字符null('\0')来分隔输出。

用find匹配并列出所有的.txt文件,然后用xargs将这些文件删除:

$ find . -type f -name "*.txt" -print0 | xargs -0 rm -f {} \;

这样就可以删除所有的.txt文件,xargs -0将\0作为输入的定界符。

统计源码目录下所有.sh的文件行数。

$ find . type f -name "*.sh" -print0 | xargs -0 wc -l
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!