web-dev-qa-db-ja.com

bashのタプルをループしますか?

Bashでタプルをループすることは可能ですか?

例として、以下がうまくいけば素晴らしいでしょう:

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

何らかの形でタプルをループさせる回避策はありますか?

68
Frank
$ 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
72
Eduardo Ivanec

このソリューションは、提出された他のものよりも少しきれいであると信じています、h/t to this 文字列を区切り文字で分割し、個々の変数に割り当てます。

for i in c,3 e,5; do 
    IFS=',' read item1 item2 <<< "${i}"
    echo "${item1}" and "${item2}"
done
16
Grant Humphries
_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))) is for i in $(seq 0 $((2-1))) is for i in $(seq 0 1) is _for i in 0 1_配列の最後の要素には、配列の長さ-1のインデックスがあるためです。

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

連想配列(辞書/ハッシュマップとも呼ばれます)を使用します。

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
6
VasiliNovikov

IFSを設定/リセットせずに@ eduardo-ivanecによって与えられた答えに基づいて、簡単に実行できます。

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

出力:

c and 3
e and 5
5
MZHm

GNU Parallel:

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
2
Ole Tange

もう少し複雑ですが、役に立つかもしれません:

a='((c,3), (e,5))'
IFS='()'; for t in $a; do [ -n "$t" ] && { IFS=','; set -- $t; [ -n "$1" ] && echo i=$1 j=$2; }; done
0
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
0
prodriguez903