我有两个长度相等的列表,各个项目中没有空格:
list1="a b c"
list2="1 2 3"
我想并行迭代这两个列表,将1与b配对,等等:
a 1
b 2
c 3
我正在尝试支持现代便携式Bourne shell,因此Bash / ksh数组不可用。如果可能的话,对awk的攻击是可以接受的,但是如果可能的话,我宁愿把它保持在纯粹的状态。
感谢您提供的任何指示!
答案 0 :(得分:13)
可能不便携(看看所有那些bash-isms!),但它很容易阅读,而其他人可能觉得它很有用......
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
答案 1 :(得分:4)
这有点hacky但是做了这个工作:
#!/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
答案 2 :(得分:4)
这应该是一个相当干净的解决方案,但除非你使用bash
的进程替代,否则它需要使用临时文件。我不知道这是否比在每次迭代中调用cut
和sed
更好或更差。
#!/bin/sh
list1="1 2 3"
list2="a b c"
echo $list1 | sed 's/ /\n/g' > /tmp/a.$$
echo $list2 | sed 's/ /\n/g' > /tmp/b.$$
paste /tmp/a.$$ /tmp/b.$$ | while read item1 item2; do
echo $item1 - $item2
done
rm /tmp/a.$$
rm /tmp/b.$$
答案 3 :(得分:2)
这应该是可移植的,并且可以使用两个以上的列表:
#!/bin/sh
x="1 2 3 4 5"
y="a b c d e"
z="A B C D E"
while
read current_x x <<EOF
$x
EOF
read current_y y <<EOF
$y
EOF
read current_z z <<EOF
$z
EOF
[ -n "$current_x" ]
do
echo "x=$current_x y=$current_y z=$current_z"
done
使用位置参数也可以。请注意,列表元素不能以“ - ”开头。否则“设置”将失败。
#!/bin/sh
x="1 2 3 4 5"
y="a b c d e"
z="A B C D E"
while
[ -n "$x" ]
do
set $x
current_x=$1
shift
x="$*"
set $y
current_y=$1
shift
y="$*"
set $z
current_z=$1
shift
z="$*"
echo "x=$current_x y=$current_y z=$current_z"
done
答案 4 :(得分:1)
NEVERMIND,SAW“BOURNE”并认为“BOURNE AGAIN”。离开这里因为它可能对某人有用,但显然不是问题的答案,对不起!
-
这有一些缺点(它不能优雅地处理不同大小的列表),但它适用于您提供的示例:
#!/bin/bash
list1="a b c"
list2="1 2 3"
c=0
for i in $list1
do
l1[$c]=$i
c=$(($c+1))
done
c=0
for i in $list2
do
echo ${l1[$c]} $i
c=$(($c+1))
done
使用常见的unix工具(如awk和cut)有更优雅的方法,但上面是按要求的纯bash实现
评论已接受的答案,它在linux或Solaris中对我没有用,问题是sed的regexp中的\ S字符类快捷方式。我用[^]替换它并且它起作用了:
#!/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
答案 5 :(得分:1)
作为一个班轮:
list2="1 2 3";
list1="a b c";
for i in $list1; do
x=`expr index "$list2" " "`;
[ $x -eq 0 ] && j=$list2 || j=${list2:0:$x};
list2=${list2:$x};
echo "$i $j";
done
答案 6 :(得分:1)
解决方案不使用数组:
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
答案 7 :(得分:1)
$ list1="1 2 3"
$ list2="a b c"
$ echo "$list1 $list2" | awk '{n=NF/2; for (i=1;i<=n;i++) print $i,$(n+i) }'
1 a
2 b
3 c
答案 8 :(得分:0)
当第一个解决方案开始出现在这里时,我一直在研究基于sed的答案。但经过进一步调查后发现,列表中的项目是用换行符分隔的,而不是空格,这让我可以选择基于头尾的解决方案:
original_revs="$(cd original && git rev-parse --all)" &&
working_revs="$(cd working && git rev-parse --all)" &&
while test -n "$original_revs"; do
original_commit="$(echo "$original_revs" | head -n 1)" &&
working_commit="$(echo "$working_revs" | head -n 1)" &&
original_revs="$(echo "$original_revs" | tail -n +2)" &&
working_revs="$(echo "$working_revs" | tail -n +2)" &&
...
done
我发布这个以防万一有人遇到问题的这个变种,但我会根据发布的问题批准接受的答案。