在 bash 中循环元组?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9713104/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 21:46:51  来源:igfitidea点击:

Loop over tuples in bash?

bashfor-loop

提问by Frank

Is it possible to loop over tuples in bash?

是否可以在 bash 中循环元组?

As an example, it would be great if the following worked:

例如,如果以下内容有效,那就太好了:

for (i,j) in ((c,3), (e,5)); do echo "$i and $j"; done

Is there a workaround that somehow lets me loop over tuples?

是否有一种解决方法可以让我遍历元组?

回答by Eduardo Ivanec

$ for i in c,3 e,5; do IFS=","; set -- $i; echo  and ; done
c and 3
e and 5

About this use of set(from man builtins):

关于set(from man builtins) 的这种用法:

Any arguments remaining after option processing are treated as values for the positional parameters and are assigned, in order, to $1, $2, ... $n

选项处理后剩余的任何参数都被视为位置参数的值,并按顺序分配给 $1, $2, ... $n

The IFS=","sets the field separator so every $igets segmented into $1and $2correctly.

IFS=","设置字段分隔符所以每天$i被分成$1$2正确。

Via this blog.

通过这个博客

Edit: more correct version, as suggested by @SLACEDIAMOND:

编辑:更正确的版本,正如@SLACEDIAMOND 所建议的:

$ OLDIFS=$IFS; IFS=','; for i in c,3 e,5; do set -- $i; echo  and ; done; IFS=$OLDIFS
c and 3
e and 5

回答by Grant Humphries

I believe this solution is a little cleaner than the others that have been submitted, h/t to thisbash style guide for illustrating how read can be used to split strings at a delimiter and assign them to individual variables.

我相信这个解决方案比其他已提交的解决方案更简洁,请参阅bash 样式指南,以说明如何使用 read 在分隔符处拆分字符串并将它们分配给各个变量。

for i in c,3 e,5; do 
    IFS=',' read item1 item2 <<< "${i}"
    echo "${item1}" and "${item2}"
done

回答by MZHm

Based on the answer given by @eduardo-ivanec without setting/resetting the IFS, one could simply do:

根据@eduardo-ivanec 给出的答案,无需设置/重置IFS,可以简单地执行以下操作:

for i in "c 3" "e 5"
do
    set -- $i
    echo  and 
done

The output:

输出:

c and 3
e and 5

回答by VasiliNovikov

Use associative array (also known as dictionary/hashMap):

使用关联数组(也称为字典/hashMap):

declare -A pairs=(
  [c]=3
  [e]=5
)
for key in "${!pairs[@]}"; do
  value="${pairs[$key]}"
  echo "key is $key and value is $value"
done

Works for bash4.0+.

适用于 bash4.0+。



If you need triples instead of pairs, you can use the more general approach:

如果您需要三元组而不是对组,您可以使用更通用的方法:

animals=(dog cat mouse)
declare -A sound=(
  [dog]=barks
  [cat]=purrs
  [mouse]=cheeps
)
declare -A size=(
  [dog]=big
  [cat]=medium
  [mouse]=small
)
for animal in "${animals[@]}"; do
  echo "$animal ${sound[$animal]} and it is ${size[$animal]}"
done

回答by user unknown

c=('a' 'c')
n=(3    4 )

for i in $(seq 0 $((${#c[*]}-1)))
do
    echo ${c[i]} ${n[i]}
done

Might sometimes be more handy.

有时可能更方便。

To explain the uglypart, as noted in the comments:

为了解释该ugly部分,如评论中所述:

seq 0 2produces the sequence of numbers 0 1 2. $(cmd) is command substitution, so for this example the output of seq 0 2, which is the number sequence. But what is the upper bound, the $((${#c[*]}-1))?

seq 0 2产生数字序列 0 1 2。 $(cmd) 是命令替换,所以对于这个例子, 的输出seq 0 2,它是数字序列。但是上限是$((${#c[*]}-1))多少?

$((somthing)) is arithmetic expansion, so $((3+4)) is 7 etc. Our Expression is ${#c[*]}-1, so something - 1. Pretty simple, if we know what ${#c[*]}is.

$((somthing)) 是算术展开式,所以 $((3+4)) 是 7 等等。我们的表达式是${#c[*]}-1,所以某事 - 1。很简单,如果我们知道是什么${#c[*]}

c is an array, c[*] is just the whole array, ${#c[*]} is the size of the array which is 2 in our case. Now we roll everything back: for i in $(seq 0 $((${#c[*]}-1)))is for i in $(seq 0 $((2-1)))is for i in $(seq 0 1)is for i in 0 1. Because the last element in the array has an index which is the length of the Array - 1.

c 是一个数组, c[*] 只是整个数组, ${#c[*]} 是数组的大小,在我们的例子中是 2。现在我们回滚一切:for i in $(seq 0 $((${#c[*]}-1)))is for i in $(seq 0 $((2-1)))is for i in $(seq 0 1)is for i in 0 1。因为数组中的最后一个元素有一个索引,它是数组的长度 - 1。

回答by kev

$ echo 'c,3;e,5;' | while IFS=',' read -d';' i j; do echo "$i and $j"; done
c and 3
e and 5

回答by Ole Tange

Using GNU Parallel:

使用 GNU 并行:

parallel echo {1} and {2} ::: c e :::+ 3 5

Or:

或者:

parallel -N2 echo {1} and {2} ::: c 3 e 5

Or:

或者:

parallel --colsep , echo {1} and {2} ::: c,3 e,5

回答by anubhava

Using printfin a process substitution:

使用printf在进程替换:

while read -r k v; do
    echo "Key $k has value: $v"
done < <(printf '%s\n' 'key1 val1' 'key2 val2' 'key3 val3')

Key key1 has value: val1
Key key2 has value: val2
Key key3 has value: val3

Above requires bash. If bashis not being used then use simple pipeline:

以上要求bash。如果bash没有被使用,那么使用简单的管道:

printf '%s\n' 'key1 val1' 'key2 val2' 'key3 val3' |
while read -r k v; do echo "Key $k has value: $v"; done

回答by prodriguez903

do echo $key $value
done < file_discriptor

for example:

例如:

$ while read key value; do echo $key $value ;done <<EOF
> c 3
> e 5
> EOF
c 3
e 5

$ echo -e 'c 3\ne 5' > file

$ while read key value; do echo $key $value ;done <file
c 3
e 5

$ echo -e 'c,3\ne,5' > file

$ while IFS=, read key value; do echo $key $value ;done <file
c 3
e 5

回答by Diego Torres Milano

A bit more involved, but may be useful:

涉及更多,但可能有用:

a='((c,3), (e,5))'
IFS='()'; for t in $a; do [ -n "$t" ] && { IFS=','; set -- $t; [ -n "" ] && echo i= j=; }; done