Apakah mungkin untuk mengulang tupel dalam bash?
Sebagai contoh, alangkah baiknya jika yang berikut berhasil:
for (i,j) in ((c,3), (e,5)); do echo "$i and $j"; done
Apakah ada solusi yang memungkinkan saya mengulang tupel?
Apakah mungkin untuk mengulang tupel dalam bash?
Sebagai contoh, alangkah baiknya jika yang berikut berhasil:
for (i,j) in ((c,3), (e,5)); do echo "$i and $j"; done
Apakah ada solusi yang memungkinkan saya mengulang tupel?
Jawaban:
$ for i in c,3 e,5; do IFS=","; set -- $i; echo $1 and $2; done
c and 3
e and 5
Tentang penggunaan set
(dari man builtins
):
Setiap argumen yang tersisa setelah pemrosesan opsi diperlakukan sebagai nilai untuk parameter posisi dan ditetapkan, secara berurutan, ke $ 1, $ 2, ... $ n
The IFS=","
menetapkan pemisah bidang sehingga setiap $i
akan tersegmentasi menjadi $1
dan $2
benar.
Melalui blog ini .
Edit: versi yang lebih benar, seperti yang disarankan oleh @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
harus disimpan dan direset ke nilai aslinya jika ini dijalankan pada baris perintah. Selain itu, yang baru IFS
bisa disetel sekali, sebelum loop dijalankan, bukan setiap iterasi.
set -- $i
IFS
, hanya mengaturnya untuk set
perintah: for i in c,3 e,5; do IFS="," set -- $i; echo $1 and $2; done
. Harap edit jawaban Anda: Jika semua pembaca hanya akan memilih satu dari solusi yang terdaftar, tidak ada gunanya membaca sejarah pengembangan lengkap. Terima kasih untuk trik keren ini!
tuples="a,1 b,2 c,3"
dan meletakkannya IFS=','
sebagai versi yang diedit, dan alih-alih c,3 e,5
menggunakannya, $tuples
itu tidak dicetak dengan baik sama sekali. Tetapi sebaliknya jika saya meletakkan IFS=','
tepat setelah do
kata kunci di loop for, itu berfungsi dengan baik saat menggunakan $tuples
serta nilai-nilai litteral. Hanya berpikir itu layak untuk dikatakan.
IFS
untuk memisahkan iterasi. yaitu Jika Anda loop atas array seperti arr=("c,3" "e,5")
dan menempatkan IFS
sebelum untuk loop, nilai $i
akan hanya c
dan e
, itu akan memisahkan diri 3
dan 5
sehingga set
tidak akan mengurai dengan benar karena $i
tidak akan memiliki apa pun untuk mengurai. Ini berarti bahwa jika nilai yang akan diiterasi tidak sebaris, nilai tersebut IFS
harus dimasukkan ke dalam loop, dan nilai luar harus sesuai dengan pemisah yang dimaksudkan untuk variabel yang akan diiterasi. Dalam kasus $tuples
itu harus sederhana IFS=
yang merupakan default dan dibagi berdasarkan spasi.
Saya percaya solusi ini sedikit lebih bersih daripada yang lain yang telah dikirimkan, h / t ke panduan gaya bash ini untuk mengilustrasikan bagaimana read dapat digunakan untuk membagi string pada pembatas dan menetapkannya ke variabel individual.
for i in c,3 e,5; do
IFS=',' read item1 item2 <<< "${i}"
echo "${item1}" and "${item2}"
done
Berdasarkan jawaban yang diberikan oleh @ eduardo-ivanec tanpa mengatur / mengatur ulang IFS
, seseorang dapat dengan mudah melakukan:
for i in "c 3" "e 5"
do
set -- $i
echo $1 and $2
done
Hasil:
c and 3
e and 5
Gunakan array asosiatif (juga dikenal sebagai kamus / 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
Bekerja untuk bash4.0 +.
Jika Anda membutuhkan tripel daripada berpasangan, Anda dapat menggunakan pendekatan yang lebih umum:
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)
, yang diinstal melalui brew, jadi YMMV.
GNU bash, version 4.3.11(1)-release-(x86_64-pc-linux-gnu)
dari Ubuntu 14.04 dalam container docker.
-A
kami punya -a
.
declare -a indices=(1 2 3); declare -a sound=(barks purrs cheeps); declare -a size=(big medium small)
dll. Belum mencobanya di terminal, tapi menurut saya itu akan berhasil.
c=('a' 'c')
n=(3 4 )
for i in $(seq 0 $((${#c[*]}-1)))
do
echo ${c[i]} ${n[i]}
done
Mungkin terkadang lebih berguna.
Untuk menjelaskan ugly
bagian tersebut, seperti yang dicatat di komentar:
seq 0 2 menghasilkan urutan angka 0 1 2. $ (cmd) adalah perintah substitusi, jadi untuk contoh ini keluarannya seq 0 2
, yaitu urutan bilangan. Tapi apa batas atasnya, itu $((${#c[*]}-1))
?
$ ((somthing)) adalah ekspansi aritmatika, jadi $ ((3 + 4)) adalah 7 dll. Ekspresi kita adalah ${#c[*]}-1
, jadi sesuatu - 1. Cukup sederhana, jika kita tahu apa ${#c[*]}
itu.
c adalah sebuah array, c [*] hanyalah seluruh array, $ {# c [*]} adalah ukuran dari array yang dalam kasus kita adalah 2. Sekarang kita roll semuanya kembali: for i in $(seq 0 $((${#c[*]}-1)))
adalah for i in $(seq 0 $((2-1)))
adalah for i in $(seq 0 1)
adalah for i in 0 1
. Karena elemen terakhir pada array memiliki indeks yang merupakan panjang dari Array - 1.
for i in $(seq 0 $(($#c[*]}-1))); do [...]
Menggunakan GNU Parallel:
parallel echo {1} and {2} ::: c e :::+ 3 5
Atau:
parallel -N2 echo {1} and {2} ::: c 3 e 5
Atau:
parallel --colsep , echo {1} and {2} ::: c,3 e,5
gnu parallel
brew install parallel
Menggunakan printf
dalam proses substitusi:
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
Di atas membutuhkan bash
. Jika bash
tidak digunakan maka gunakan pipa sederhana:
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
sebagai contoh:
$ 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
Sedikit lebih terlibat, tetapi mungkin berguna:
a='((c,3), (e,5))'
IFS='()'; for t in $a; do [ -n "$t" ] && { IFS=','; set -- $t; [ -n "$1" ] && echo i=$1 j=$2; }; done
Tetapi bagaimana jika tupel lebih besar dari k / v yang dapat ditampung oleh array asosiatif? Bagaimana jika itu 3 atau 4 elemen? Seseorang dapat mengembangkan konsep ini:
###---------------------------------------------------
### 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
Maka hasilnya akan terlihat seperti:
$ ./assoc-array-tinkering.sh
Print all elements in the array...
ya1 - ya2 - ya3 - ya4
ye1 - ye2 - ye3 - ye4
yo1 - yo2 - yo3 - yo4
Dan jumlah elemen sekarang tidak terbatas. Tidak mencari suara; hanya berpikir keras. REF1 , REF2
Dalam kasus di mana definisi tupel saya lebih kompleks, saya lebih suka memilikinya dalam heredoc:
while IFS=", " read -ra arr; do
echo "${arr[0]} and ${arr[1]}"
done <<EOM
c, 3
e, 5
EOM
Ini menggabungkan perulangan baris dari heredoc dengan memisahkan baris pada beberapa karakter pemisah yang diinginkan .