Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在bash中循环元组?_Bash_For Loop - Fatal编程技术网

在bash中循环元组?

在bash中循环元组?,bash,for-loop,Bash,For Loop,可以在bash中循环元组吗 举个例子,如果以下方法有效,那就太好了: 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 关于set(来自man内置)的使用: 选项处理后剩余的任何参数都被视为值 用于位置参数,并按顺序指定给$1、$2,

可以在bash中循环元组吗

举个例子,如果以下方法有效,那就太好了:

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
关于
set
(来自
man内置
)的使用:

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

IFS=“,”
设置字段分隔符,以便将每个
$i
正确分割为
$1
$2

通过

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

$ 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

更复杂一点,但可能有用:

a='((c,3), (e,5))'
IFS='()'; for t in $a; do [ -n "$t" ] && { IFS=','; set -- $t; [ -n "$1" ] && echo i=$1 j=$2; }; done
有时可能更方便

要解释注释中提到的
丑陋部分

seq 0 2生成数字0 1 2的序列$(cmd)是命令替换,因此在本例中,
seq 0 2
的输出是数字序列。但是,
$(${c[*]}-1))
的上限是什么

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

c是一个数组,c[*]就是整个数组,${#c[*]}是数组的大小,在我们的例子中是2。现在我们回滚所有内容:
对于i in$(seq 0$(${c[*]}-1))
对于i in$(seq 0$((2-1))
对于i in$(seq 01)
对于i in 01
。因为数组中的最后一个元素有一个索引,该索引是数组的长度-1。

bash style guide说明了如何使用
read
在分隔符处拆分字符串并将其分配给各个变量。因此,使用该技术,您可以解析字符串,并使用一个类似于下面循环中的一个线性函数分配变量:

用于c、3e、5中的i;做
如果使用GNU Parallel读取item1 item2:

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

或:

使用关联数组(也称为字典/哈希映射):

适用于bash4.0+


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

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

根据@eduardo ivanec给出的答案,在不设置/重置
IFS
的情况下,可以简单地执行以下操作:

for i in "c 3" "e 5"
do
    set -- $i
    echo $1 and $2
done
输出:

c and 3
e and 5
do echo$key$value
完成
例如:

$ 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
$读取键值时;不回显$key$value;完成e 5
>EOF
C3
e 5
$echo-e'c 3\ne 5'>文件
$while读取键值;不回显$key$value;完成文件

$while if=,读取键值;不回显$key$value;在过程替换中使用
printf
完成:

while read -r k v; do
    echo "Key $k has value: $v"
done < <(printf '%s\n' 'key1 val1' 'key2 val2' 'key3 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

但是,如果元组大于关联数组可以容纳的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

元素的数量现在没有限制。不寻求选票;只是大声地思考

在元组定义更复杂的情况下,我更喜欢将它们放在heredoc中:

while IFS=", " read -ra arr; do
  echo "${arr[0]} and ${arr[1]}"
done <<EOM
c, 3
e, 5
EOM
而IFS=“,”读取-ra-arr;做
回显“${arr[0]}和${arr[1]}”

做得很好——只想指出,如果在命令行上运行,则应保存
IFS
,并重置为其原始值。此外,新的
IFS
可以在循环运行之前设置一次,而不是每次迭代。如果任何$i以连字符开头,则更安全的做法是
set--$i
而不是保存
IFS
,只为
set
命令设置它:
用于c中的i,3 e,5;do IFS=“,”设置--$i;echo 1美元和2美元;完成
。请编辑您的答案:如果所有读者只选择列出的解决方案中的一个,那么阅读完整的开发历史是没有意义的。谢谢你这个酷把戏!如果我声明
tuples=“a,1b,2c,3”
并将
IFS=”,“
放在编辑版本中,而不是使用
c,3e,5
使用
$tuples
,那么它根本打印不好。但是,如果我将
IFS=','
放在for循环中的
do
关键字之后,则在使用
$tuples
以及其他值时,它会很好地工作。只是觉得值得一提。@Simonlbc这是因为for循环使用
IFS
来分割迭代。i、 e.如果你循环一个数组,比如
arr=(“c,3”“e,5”)
,并将
IFS
放在for循环之前,
$i
的值将只是
c
e
,它将分开
3
5
,因此
set
将无法正确解析,因为
$i
将没有任何要解析的内容。这意味着,如果要迭代的值不是内联的,则应将
IFS
放在循环内,外部值应遵循要迭代的变量的预期分隔符。在
$tuples
的情况下,它应该是简单的
IFS=
,这是默认值,并在空白处拆分;做[…]
哇,这赢得了“我今天看到的最丑的一群武断角色”奖。有人想解释一下这个讨厌的东西到底是干什么的吗?我在散列符号处迷路了…@koniiik:解释补充道。“Neu Perl:复仇”我想用Perl会更清楚。:-)来自python的背景,这确实是一个非常有用的问题!四年后再看这个,我想知道是否还有更好的方法。天哪,差不多8年后,我也在想,是否还有更好的方法可以做到这一点。但这个答案在我看来相当不错:不喜欢这个?很好地让我克服了惯性,安装了
gnu parallel
brew安装parallel
FYI,这对我在Mac上使用
gnu bash,版本4.4.23(1)-release-(x86\u 64-apple-darwin17.5.0)
不起作用,它是通过brew安装的,所以YMMV
do 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
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
printf '%s\n' 'key1 val1' 'key2 val2' 'key3 val3' |
while read -r k v; do echo "Key $k has value: $v"; done
###---------------------------------------------------
### 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
while IFS=", " read -ra arr; do
  echo "${arr[0]} and ${arr[1]}"
done <<EOM
c, 3
e, 5
EOM