簡體   English   中英

在 bash 中循環元組?

[英]Loop over tuples in bash?

是否可以在 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 builtins ):

選項處理后剩余的任何參數都被視為位置參數的值,並按順序分配給 $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

這個bash 風格指南說明了如何使用read在分隔符處拆分字符串並將它們分配給各個變量。 因此,使用該技術,您可以解析字符串並使用如下循環中的單行代碼分配變量:

for i in c,3 e,5; do 
    IFS=',' read item1 item2 <<< "${i}"
    echo "${item1}" and "${item2}"
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

使用關聯數組(也稱為字典/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

適用於 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
c=('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))

$((somthing)) 是算術展開式,所以 $((3+4)) 是 7 等等。我們的表達式是${#c[*]}-1 ,所以有些東西 - 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。

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

使用 GNU 並行:

parallel 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

但是如果元組大於關聯數組可以容納的 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

並且元素的數量現在沒有限制。 不求選票; 只是大聲思考。 REF1 , REF2

在進程替換中使用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
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

在我的元組定義更復雜的情況下,我更喜歡將它們放在 heredoc 中:

while IFS=", " read -ra arr; do
  echo "${arr[0]} and ${arr[1]}"
done <<EOM
c, 3
e, 5
EOM

這將循環遍歷heredoc的行與在某些所需的分隔符處拆分行相結合。

涉及更多,但可能有用:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM