shell技巧-xargs代替for循环格式化多列数据

shell技巧-xargs代替for循环格式化多列数据

之前对xargs命令理解不够透彻,在shell脚本中对于多列文本格式化参数一直用for来实现,最近深入研究了一下,xargs可以完全代替for循环使用!

假设这里有一个包含两列内容的txt文本(ip和port)。

[root@VM-0-15-centos test]# cat ip-port.txt 
222.69.242.108  80
47.100.103.111  80
119.3.228.163   8888
139.159.156.229 9080
116.63.90.90    9443

我想用curl去批量请求这些ip获取状态码,按照我以往的写法如下:

[root@VM-0-15-centos test]# for i in $(cat ip-port.txt | awk '{printf "%s:%s\n",$1,$2}');do curl -m1 -s -o /dev/null -w "%{http_code} %{url_effective}\n" $i ;done 
302 HTTP://222.69.242.108:80/
000 HTTP://47.100.103.111:80/
302 HTTP://119.3.228.163:8888/
302 HTTP://139.159.156.229:9080/
000 HTTP://116.63.90.90:9443/

这样可以实现,但是写法过于复杂。在for循环之前还需要用awk格式化输出。

之前误认为xargs无法处理多列的数据,但实际是可以通过一些trick来实现。

换成xargs的写法如下:

[root@VM-0-15-centos test]# cat ip-port.txt | xargs -n2 sh -c 'curl -m1 -s -o /dev/null -w "%{http_code} %{url_effective}\n" $1:$2' _   
302 HTTP://222.69.242.108:80/
000 HTTP://47.100.103.111:80/
302 HTTP://119.3.228.163:8888/
000 HTTP://139.159.156.229:9080/
000 HTTP://116.63.90.90:9443/

使用xargs调用sh就巧妙地省略了字符串单独格式化处理的步骤!

注意:

  • xargs命令最后还有一个下划线一定不能省略!
  • sh -c 后面的命令要用单引号,否则$1,$2会被当前shell当作变量解析!

由于使用了sh -c ,相当于调用了一个子shell。而shell中的参数传递如下:

  • $0 Shell本身的文件名
  • $1~$n 添加到Shell的各参数值。$1是第1参数、$2是第2参数…。

如果不加下划线会怎么样?

[root@VM-0-15-centos test]# cat ip-port.txt | xargs -n2 sh -c 'curl -m1 -s -o /dev/null -w "%{http_code} %{url_effective}\n" $1:$2' 
000 HTTP://80:/
000 HTTP://80:/
000 HTTP://8888:/
000 HTTP://9080:/
000 HTTP://9443:/

$1实际取到的是第二列的参数,而$2为空值。此时$0才是第一列的内容!

为什么会这样呢?查阅了sh的文档,bash也一样,解释如下:

-c string 如果有-c选项,那么命令将从字符串中读取。 如果字符串后面有参数,它们将被分配给位置参数。参数从$0开始。

man sh

使用-c参数相当于默认没有shell文件名,默认传参就是从$0开始。但是这不符合我们的使用习惯,所以在命令最后加上一个下划线代替文件名作为$0。这样参数就从$1开始了。

至于n2的作用还是解释一下,分为两列。

[root@VM-0-15-centos test]# head -5 ip-port.txt | xargs 
222.69.242.108 80 47.100.103.111 80 119.3.228.163 8888 139.159.156.229 9080 116.63.90.90 9443
[root@VM-0-15-centos test]# head -5 ip-port.txt | xargs -n2
222.69.242.108 80
47.100.103.111 80
119.3.228.163 8888
139.159.156.229 9080
116.63.90.90 9443

补充:上面curl的状态码有些是000,因为我超时时间设置为1s,部分请求在1s内请求未完成导致的。

Print Friendly, PDF & Email
赞赏

微信赞赏支付宝赞赏

Zgao

愿有一日,安全圈的师傅们都能用上Zgao写的工具。