在 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
Loop over tuples in bash?
提问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 $i
gets segmented into $1
and $2
correctly.
该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 ugly
part, 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 printf
in 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 bash
is 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