Apa cara terbaik untuk meniru loop do-while di Bash?
Saya dapat memeriksa kondisi sebelum memasuki while
loop, dan kemudian melanjutkan memeriksa kembali kondisi dalam loop, tetapi itu adalah kode duplikat. Apakah ada cara yang lebih bersih?
Kode semu dari skrip saya:
while [ current_time <= $cutoff ]; do
check_if_file_present
#do other stuff
done
Ini tidak berfungsi check_if_file_present
jika diluncurkan setelah $cutoff
waktu tersebut, dan do-while akan melakukannya.
until
sakelar?until
juga akan mengevaluasi kondisi sebelum menjalankan badan loopJawaban:
Dua solusi sederhana:
Jalankan kode Anda sekali sebelum while loop
actions() { check_if_file_present # Do other stuff } actions #1st execution while [ current_time <= $cutoff ]; do actions # Loop execution done
Atau:
while : ; do actions [[ current_time <= $cutoff ]] || break done
sumber
:
adalah bawaan, setara dengan bawaantrue
. Mereka berdua "tidak melakukan apa pun dengan sukses".true
adalah program aktual sedangkan:
bawaan. Yang pertama hanya keluar dengan0
(danfalse
dengan1
) yang terakhir sama sekali tidak melakukan apa-apa. Anda bisa mengeceknya denganwhich true
.:
masih dapat digunakan sebagai penggantitrue
di Bash. Cobalah denganwhile :; do echo 1; done
.true
bukan Bash bawaan. Ini adalah program yang biasanya ditemukan di/bin
.type true
di bash (kembali ke bash 3.2) kembalitrue is a shell builtin
. Memang benar itu/bin/true
adalah sebuah program; apa yang tidak benar tentang yang benar adalah itutrue
bukan bawaan. (tl; dr: true adalah bash builtin DAN program)Tempatkan badan loop Anda setelah
while
dan sebelum tes. Badanwhile
loop yang sebenarnya harus berupa no-op.while check_if_file_present #do other stuff (( current_time <= cutoff )) do : done
Alih-alih titik dua, Anda dapat menggunakan
continue
jika menurut Anda lebih mudah dibaca. Anda juga dapat memasukkan perintah yang hanya akan berjalan di antara iterasi (bukan sebelum pertama atau setelah terakhir), sepertiecho "Retrying in five seconds"; sleep 5
. Atau cetak pembatas antar nilai:i=1; while printf '%d' "$((i++))"; (( i <= 4)); do printf ','; done; printf '\n'
Saya mengubah tes untuk menggunakan tanda kurung ganda karena Anda tampaknya membandingkan bilangan bulat. Di dalam tanda kurung siku ganda, operator pembanding seperti
<=
bersifat leksikal dan akan memberikan hasil yang salah saat membandingkan 2 dan 10, misalnya. Operator tersebut tidak bekerja di dalam tanda kurung siku tunggal.sumber
while { check_if_file_present; ((current_time<=cutoff)); }; do :; done
? Yaitu apakah perintah di dalamwhile
kondisi secara efektif dipisahkan oleh titik koma bukan oleh misalnya&&
, dan dikelompokkan oleh{}
?&&
atau||
karena hal itu secara efektif menjadikannya bagian dari pengujian yang mengontrolwhile
. Kecuali Anda menggunakan konstruksi ini pada baris perintah, saya tidak akan melakukannya sebagai satu baris (dalam skrip, khususnya) karena maksudnya tidak dapat dibaca.while false; false; false; true; do echo here; break; done
outputs "here"Kita dapat meniru loop do-while di Bash dengan
while [[condition]]; do true; done
seperti ini:while [[ current_time <= $cutoff ]] check_if_file_present #do other stuff do true; done
Sebagai contoh. Berikut implementasi saya untuk mendapatkan koneksi ssh dalam skrip bash:
#!/bin/bash while [[ $STATUS != 0 ]] ssh-add -l &>/dev/null; STATUS="$?" if [[ $STATUS == 127 ]]; then echo "ssh not instaled" && exit 0; elif [[ $STATUS == 2 ]]; then echo "running ssh-agent.." && eval `ssh-agent` > /dev/null; elif [[ $STATUS == 1 ]]; then echo "get session identity.." && expect $HOME/agent &> /dev/null; else ssh-add -l && git submodule update --init --recursive --remote --merge && return 0; fi do true; done
Ini akan memberikan keluaran secara berurutan seperti di bawah ini:
Step #0 - "gcloud": intalling expect.. Step #0 - "gcloud": running ssh-agent.. Step #0 - "gcloud": get session identity.. Step #0 - "gcloud": 4096 SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /builder/home/.ssh/id_rsa (RSA) Step #0 - "gcloud": Submodule '.google/cloud/compute/home/chetabahana/.docker/compose' ([email protected]:chetabahana/compose) registered for path '.google/cloud/compute/home/chetabahana/.docker/compose' Step #0 - "gcloud": Cloning into '/workspace/.io/.google/cloud/compute/home/chetabahana/.docker/compose'... Step #0 - "gcloud": Warning: Permanently added the RSA host key for IP address 'XXX.XX.XXX.XXX' to the list of known hosts. Step #0 - "gcloud": Submodule path '.google/cloud/compute/home/chetabahana/.docker/compose': checked out '24a28a7a306a671bbc430aa27b83c09cc5f1c62d' Finished Step #0 - "gcloud"
sumber
Implementasi ini:
do=true while $do || conditions; do do=false # your code ... done
Ia bekerja dengan loop baca, juga, melewatkan pembacaan pertama:
do=true while $do || read foo; do do=false # your code ... echo $foo done
sumber