最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501
当前位置: 首页 - 科技 - 知识百科 - 正文

Bash实用技巧:同时循环两个列表

来源:懂视网 责编:小采 时间:2020-11-09 08:13:55
文档

Bash实用技巧:同时循环两个列表

Bash实用技巧:同时循环两个列表:摘要: 你会学到一种原创的同时循环两个列表的方法。类似于Python或者Haskell的zip函数,非常简洁直观,效果如下: $ paste ( seq 1 5 ) ( seq 129 133 ) | while read host ip; do echo vm$host: 172.16.116.$ip
推荐度:
导读Bash实用技巧:同时循环两个列表:摘要: 你会学到一种原创的同时循环两个列表的方法。类似于Python或者Haskell的zip函数,非常简洁直观,效果如下: $ paste ( seq 1 5 ) ( seq 129 133 ) | while read host ip; do echo vm$host: 172.16.116.$ip

摘要: 你会学到一种原创的同时循环两个列表的方法。类似于Python或者Haskell的zip函数,非常简洁直观,效果如下: $ paste ( seq 1 5 ) ( seq 129 133 ) | while read host ip; do echo " vm$host: 172.16.116.$ip " ; done vm1: 172.16 . 116.129 vm2: 172

摘要:

你会学到一种原创的同时循环两个列表的方法。类似于Python或者Haskell的zip函数,非常简洁直观,效果如下:

$ paste <(seq 1 5) <(seq 129 133) | while read host ip; do echo "vm$host: 172.16.116.$ip"; done

vm1: 172.16.116.129
vm2: 172.16.116.130
vm3: 172.16.116.131
vm4: 172.16.116.132
vm5: 172.16.116.133

详情:

在实际应用中,经常需要我们输入对应的两个列表,比如主机名和IP:

vm110 172.18.11.129

vm111 172.18.11.130

...

如果有很多的话,使用awk处理一个临时文件,然后使用while read来循环是不错的(例如从Excel里面拷贝成文本文件,然后用awk提取相应的列到一个文件):

awk '{print $1 $3}' orig.txt | while read host ip; do echo $host : $ip; done < temp.txt

但是,有没有能直接在命令行上生成这些列表并循环的方法呢?因为我更喜欢用for i in vm{110..120}; do echo $i; done这种方式来循环列表,但是这种方式只支持一个列表,怎么找到对应的另一个列表呢?

直接google,就会发现没有什么好的方法(以下均来自StackOverflow):

1、有的直接使用bash的数组甚至hash表,都是较新的版本才有,然后使用数字index来循环。这种方法一点也不直观:

list1="a b c"
list2="1 2 3"
array1=($list1)
array2=($list2)

count=${#array1[@]}
for i in `seq 1 $count`
do
 echo ${array1[$i-1]} ${array2[$i-1]}
done

谁也不想写类似${#array1[@]}这样的复杂表达,因为我们不是在编程,而是在输入一条命令。

2、有的使用了各种正则表达式命令,我一眼看不出来什么意思,没人会为了循环两个列表,去专门写一个脚本文件:

#!/bin/sh
list1="1 2 3"
list2="a b c"
while [ -n "$list1" ]
do
 head1=`echo "$list1" | cut -d ' ' -f 1`
 list1=`echo "$list1" | sed 's/[^ ]* *\(.*\)$/\1/'`
 head2=`echo "$list2" | cut -d ' ' -f 1`
 list2=`echo "$list2" | sed 's/[^ ]* *\(.*\)$/\1/'`
 echo $head1 $head2
done

还有其他几种,有兴趣的可以去看看,http://stackoverflow.com/questions/546817/iterating-over-two-lists-in-parallel-in-bin-sh。

但是有一种方法提醒了我:

list1="aaa1 aaa2 aaa3"
list2="bbb1 bbb2 bbb3"

tmpfile1=$( mktemp /tmp/list.XXXXXXXXXX ) || exit 1
tmpfile2=$( mktemp /tmp/list.XXXXXXXXXX ) || exit 1

echo $list1 | tr ' ' '\n' > $tmpfile1
echo $list2 | tr ' ' '\n' > $tmpfile2

paste $tmpfile1 $tmpfile2

rm --force $tmpfile1 $tmpfile2

这种方法创建了两个临时文件,好像还不如前面的方法,但是在我看来,这很有启发性:他使用了paste来结合两个列表,这是linux下原生的合并列表命令,相当于其他语言的zip。

另外,临时文件也可以避免,因此我想出了以下的方法(并不推荐):

paste <(echo vm{1..5} | tr ' ' '\n') <(echo 172.16.116.{129..133} | tr ' ' '\n') | while read host ip; do echo $host: $ip; done

其中vm{1..5}会产生“vm1 vm2 vm3 vm4 vm5”,以空格分隔,而paste是把两个列文件合并成一个,所以必须把空格替换成换行,这就是tr做的事。明显使用tr很不好,增加了命令的复杂度。

另外<()是执行一个命令,并把这个命令输出当作一个文件的意思。

于是我想到了seq,好像可以指定分隔符,一查文档,居然默认就是换行,于是命令得以大幅简化:

paste <(seq 1 5) <(seq 129 133) | while read host ip; do echo "vm$host: 172.16.116.$ip"; done

这个命令可以循环2个及以上同等长度的列表,而且非常直观。就是开头提到的方法。

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文档

Bash实用技巧:同时循环两个列表

Bash实用技巧:同时循环两个列表:摘要: 你会学到一种原创的同时循环两个列表的方法。类似于Python或者Haskell的zip函数,非常简洁直观,效果如下: $ paste ( seq 1 5 ) ( seq 129 133 ) | while read host ip; do echo vm$host: 172.16.116.$ip
推荐度:
标签: 两个 列表 学到
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top