bashでタプルをループすることは可能ですか?
例として、以下が機能する場合は素晴らしいでしょう:
for (i,j) in ((c,3), (e,5)); do echo "$i and $j"; done
どういうわけかタプルをループさせる回避策はありますか?
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
IFS
ね。コマンドラインで実行する場合は、保存して元の値にリセットする必要があることを指摘しておきます。また、newIFS
は、すべての反復ではなく、ループが実行される前に1回設定できます。
set -- $i
IFS
、set
次のコマンドにのみ設定しますfor i in c,3 e,5; do IFS="," set -- $i; echo $1 and $2; done
。あなたの答えを編集してください:すべての読者がリストされた解決策の1つだけを選ぶなら、完全な開発履歴を読まなければならないことに意味がありません。このクールなトリックをありがとう!
tuples="a,1 b,2 c,3"
して入れた場合IFS=','
、c,3 e,5
使用$tuples
する代わりにまったく印刷されません。しかし、代わりに、forループのキーワードのIFS=','
直後に置くと、文字通りの値だけでdo
なく、使用するときに$tuples
もうまく機能します。言う価値があると思っただけです。
IFS
反復の分割に使用するためです。あなたのような配列をループした場合すなわちarr=("c,3" "e,5")
と入れてIFS
forループの前に、の値が$i
ちょうどになりますc
とe
、それが離れて分割されます3
し、5
そのset
ため正しく解析しません$i
解析には何もありません。つまり、反復する値がインライン化されていない場合はIFS
、をループの内側に配置し、外側の値は、反復する変数の目的の区切り文字を尊重する必要があります。それの場合、$tuples
それは単にIFS=
デフォルトであり、空白で分割されるはずです。
私は、このソリューションはに、H / Tを提出されている他のものより少しきれいであると信じて、この区切り文字で分割された文字列に使用し、個々の変数に割り当てることができますどのように読んで説明するために、bashのスタイルガイド。
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
連想配列(dictionary / 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
GNU bash, version 4.4.23(1)-release-(x86_64-apple-darwin17.5.0)
、これはbrew経由でインストールされたMacでは機能しなかったのでYMMV。
GNU bash, version 4.3.11(1)-release-(x86_64-pc-linux-gnu)
Dockerコンテナ内のUbuntu14.04からは機能しました。
-A
、我々は持っています-a
。
declare -a indices=(1 2 3); declare -a sound=(barks purrs cheeps); declare -a size=(big medium small)
などしているが、端末でそれを試していない、まだ、私はそれが動作するはずだと思います。
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の長さであるインデックスがあるためです。
for i in $(seq 0 $(($#c[*]}-1))); do [...]
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
gnu parallel
brew install parallel
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
もう少し複雑ですが、役立つ場合があります。
a='((c,3), (e,5))'
IFS='()'; for t in $a; do [ -n "$t" ] && { IFS=','; set -- $t; [ -n "$1" ] && echo i=$1 j=$2; }; 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
その場合、出力は次のようになります。
$ ./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
これは、ヒアドキュメントの行をループすることと、必要な区切り文字で行を分割することを組み合わせたものです。