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


88

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

例として、以下が機能する場合は素晴らしいでしょう:

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

どういうわけかタプルをループさせる回避策はありますか?


4
Pythonのバックグラウンドから来ているので、これは非常に便利な質問です。
John Jiang

5
4年後のこれを見て、これを行うためのより良い方法はまだないのだろうかと思います。ああ、神様。
giszmo 2016年

ほぼ8年後、私はこれを行うためのより良い方法がまだないかどうかも疑問に思いました。しかし、この2018年の答えは私にはかなり良いに見える:stackoverflow.com/a/52228219/463994
MountainX

回答:


87
$ 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

7
いいですIFSね。コマンドラインで実行する場合は、保存して元の値にリセットする必要があることを指摘しておきます。また、newIFSは、すべての反復ではなく、ループが実行される前に1回設定できます。
Eggxactly 2012年

1
$ iのいずれかがハイフンで始まる場合は、より安全set -- $i
です

1
保存する代わりにIFSset次のコマンドにのみ設定しますfor i in c,3 e,5; do IFS="," set -- $i; echo $1 and $2; done。あなたの答えを編集してください:すべての読者がリストされた解決策の1つだけを選ぶなら、完全な開発履歴を読まなければならないことに意味がありません。このクールなトリックをありがとう!
cfi 2015年

編集したバージョンのように宣言tuples="a,1 b,2 c,3"して入れた場合IFS=','c,3 e,5使用$tuplesする代わりにまったく印刷されません。しかし、代わりに、forループのキーワードのIFS=','直後に置くと、文字通りの値だけでdoなく、使用するときに$tuplesもうまく機能します。言う価値があると思っただけです。
Simonlbc 2016年

@Simonlbcは、forループがIFS反復の分割に使用するためです。あなたのような配列をループした場合すなわちarr=("c,3" "e,5")と入れてIFSforループの前に、の値が$iちょうどになりますce、それが離れて分割されます3し、5そのsetため正しく解析しません$i解析には何もありません。つまり、反復する値がインライン化されていない場合はIFS、をループの内側に配置し、外側の値は、反復する変数の目的の区切り文字を尊重する必要があります。それの場合、$tuplesそれは単にIFS=デフォルトであり、空白で分割されるはずです。
2017年

25

私は、このソリューションはに、H / Tを提出されている他のものより少しきれいであると信じて、この区切り文字で分割された文字列に使用し、個々の変数に割り当てることができますどのように読んで説明するために、bashのスタイルガイド。

for i in c,3 e,5; do 
    IFS=',' read item1 item2 <<< "${i}"
    echo "${item1}" and "${item2}"
done

17

を設定/リセットせずに@ eduardo-ivanecによって与えられた回答に基づいて、次のようにするIFSことができます。

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

出力:

c and 3
e and 5

このアプローチは、受け入れられ、最も支持されているアプローチよりもはるかに単純に思えます。@Eduardo Ivanecが提案したのとは対照的に、この方法でそれを行わない理由はありますか?
spurra

@spurraこの回答は6年半最近のものであり、それに基づいています。期日が到来したクレジット。
ディエゴ

1
@Diego私はそれを知っています。それは答えにはっきりと書かれています。私は、受け入れられた答えに対してこのアプローチを使用しない理由があるかどうか尋ねていました。
spurra

2
@spurraあなたはデフォルトのセパレータ(スペース、タブまたは改行)が何らかの理由であなたのための(動作しない場合エドゥアルドの答えを使用したいと思いますbash.cyberciti.biz/guide/$IFS
ディエゴ・

11

連想配列(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からは機能しました。
デビッド

古いバージョンのbashまたはこの機能をサポートしていないバージョンはインデックスベースで機能しないようですか?ここで、キーは文字列ではなく数字です。tldp.org/LDP/abs/html/declareref.html、そして代わりに-A、我々は持っています-a
デビッド

デビッド、そうだね。配列インデックスを試して「結合性」を取得できると思います。同様declare -a indices=(1 2 3); declare -a sound=(barks purrs cheeps); declare -a size=(big medium small)などしているが、端末でそれを試していない、まだ、私はそれが動作するはずだと思います。
VasiliNovikov

7
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の長さであるインデックスがあるためです。


1
あなたがすべきことfor i in $(seq 0 $(($#c[*]}-1))); do [...]
reox 2013年

1
うわー、これは「私が今日見た任意のキャラクターの最も醜い束」賞を受賞します。誰かがこの忌まわしきが正確に何をするのか説明したいと思いますか?私は、ハッシュ記号...で失われてしまった
koniiiik

1
@koniiiik:説明が追加されました。
ユーザー不明

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

3

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

1
これは好きじゃない?よく作られた私は慣性を克服し、インストールgnu parallel
StephenBoesch

2
brew install parallel
StephenBoesch 2017

2

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

1
はい!アヌババ、あなたは甘い天才です!
スコット

1
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

もう少し複雑ですが、役立つ場合があります。

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

しかし、タプルが連想配列が保持できる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

そして、要素の数に制限はありません。投票を探していません。大声で考えているだけです。REF1REF2


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.