在Bash中是否可以循环遍历元组?
举个例子,如果以下代码能够正常工作就太好了:
有没有一种方法可以让我以某种方式循环遍历元组?
举个例子,如果以下代码能够正常工作就太好了:
for (i,j) in ((c,3), (e,5)); do echo "$i and $j"; done
有没有一种方法可以让我以某种方式循环遍历元组?
for (i,j) in ((c,3), (e,5)); do echo "$i and $j"; done
$ for i in c,3 e,5; do IFS=","; set -- $i; echo $1 and $2; done
c and 3
e and 5
$ OLDIFS=$IFS; IFS=','; for i in c,3 e,5; do set -- $i; echo $1 and $2; done; IFS=$OLDIFS
c and 3
e and 5
set -- $i
。 - glenn jackmanIFS
,只需为set
命令设置它:for i in c,3 e,5; do IFS="," set -- $i; echo $1 and $2; done
。请编辑您的答案:如果所有读者都只选择列出的解决方案之一,那么阅读完整的开发历史就没有意义了。感谢这个酷炫的技巧! - cfituples="a,1 b,2 c,3"
并在编辑版本中设置IFS=','
,并且使用$tuples
而不是c,3 e,5
,则它根本无法正常打印。
但是,如果我将IFS=','
放在for循环中的do
关键字之后,那么当使用$tuples
以及文字值时,它就能够正常工作。只是觉得值得一提。 - Simonlbcfor
循环使用 IFS
来分割迭代。例如,如果您循环遍历一个数组 arr=("c,3" "e,5")
并在 for
循环之前放置 IFS
,那么 $i
的值将只是 c
和 e
,它会分离掉 3
和 5
,所以 set
不会正确解析,因为 $i
没有任何要解析的内容。这意味着,如果要迭代的值不是内联的,则应该将 IFS
放在循环内部,并且外部值应该遵守要迭代的变量的预期分隔符。在 $tuples
的情况下,它应该是简单的 IFS=
,这是默认值,并在空格上拆分。 - untorefor i in "c 3" "e 5"
do
set -- $i # Convert the "tuple" into the param args $1 $2...
echo $1 and $2
done
c and 3
e and 5
$1
和 $2
作为参数传递,那么您该怎么办呢?也就是说,如何区分传递的第一个和第二个参数与元组的第一个和第二个项目? - mfaaniread
来在分隔符处拆分字符串并将它们赋值给单独的变量。因此,使用这种技术,你可以像下面的循环中的一行代码那样解析字符串并赋值给变量。for i in c,3 e,5; do
IFS=',' read item1 item2 <<< "${i}"
echo "${item1}" and "${item2}"
done
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
GNU bash, version 4.3.11(1)-release-(x86_64-pc-linux-gnu)
上工作。 - Daviddeclare -a indices=(1 2 3); declare -a sound=(barks purrs cheeps); declare -a size=(big medium small)
等等。虽然我还没有在终端中尝试过,但我认为它应该可以工作。 - VasiliNovikovc=('a' 'c')
n=(3 4 )
for i in $(seq 0 $((${#c[*]}-1)))
do
echo ${c[i]} ${n[i]}
done
有时可能更方便。
解释一下评论中提到的 ugly
部分:
seq 0 2 生成数字序列 0 1 2。$(cmd) 是命令替换,因此对于这个例子,输出是 seq 0 2
的输出,即数字序列。但是上限是什么,$((${#c[*]}-1))
是什么?
$((something)) 是算术扩展,所以 $((3+4)) 是 7 等等。我们的表达式是 ${#c[*]}-1
,因此 something - 1。如果我们知道 ${#c[*]}
是什么,那就很简单了。
c 是一个数组,c[*] 就是整个数组,${#c[*]} 是数组的大小,在我们的情况下是 2。现在我们回顾一下: for i in $(seq 0 $((${#c[*]}-1)))
是 for i in $(seq 0 $((2-1)))
是 for i in $(seq 0 1)
是 for i in 0 1
。因为数组中最后一个元素的索引是数组长度减 1。
for i in $(seq 0 $(($#c[*]}-1))); do [...]
。 - reox$ echo 'c,3;e,5;' | while IFS=',' read -d';' i j; do echo "$i and $j"; done
c and 3
e and 5
但是如果元组比关联数组可以容纳的k/v更大怎么办? 如果它有3或4个元素怎么办? 我们可以在这个概念上进行扩展:
###---------------------------------------------------
### VARIABLES
###---------------------------------------------------
myVars=(
'ya1,ya2,ya3,ya4'
'ye1,ye2,ye3,ye4'
'yo1,yo2,yo3,yo4'
)
###---------------------------------------------------
### MAIN PROGRAM
###---------------------------------------------------
### Echo all elements in the array
###---
printf '\n\n%s\n' "Print all elements in the array..."
for dataRow in "${myVars[@]}"; do
while IFS=',' read -r var1 var2 var3 var4; do
printf '%s\n' "$var1 - $var2 - $var3 - $var4"
done <<< "$dataRow"
done
$ ./assoc-array-tinkering.sh
Print all elements in the array...
ya1 - ya2 - ya3 - ya4
ye1 - ye2 - ye3 - ye4
yo1 - yo2 - yo3 - yo4
brew install shellcheck bash dash bash-completion@2
。这将获得最新的GNU bash - 就像在Linux上一样; 所以无论哪里都是相同的 :-) - todd_dsmecho $SHELL
时才是必需的。在新的macOS上,它应该是ZSH;在这种情况下,请给自己一个方便并安装Oh My ZSH - 它更加出色。 - todd_dsmparallel echo {1} and {2} ::: c e :::+ 3 5
或者:
parallel -N2 echo {1} and {2} ::: c 3 e 5
或者:
parallel --colsep , echo {1} and {2} ::: c,3 e,5
gnu parallel
。 - WestCoastProjectsbrew install parallel
- WestCoastProjectsdo echo $key $value
done < file_discriptor
$ 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
在进程替换中使用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
bash
。如果没有使用 bash
,则可以使用简单的管道:printf '%s\n' 'key1 val1' 'key2 val2' 'key3 val3' |
while read -r k v; do echo "Key $k has value: $v"; done