Η Bash έχει δύο μορφές επανάληψης:
for
Για να διατρέξουμε μια λίστα στοιχείων, χρησιμοποιούμε τον βρόχο for.
for varname in words; do COMMANDS; done
Το words επεκτείνεται με διαχωρισμό λέξεων και επέκταση ονομάτων αρχείων (που τα μάθαμε στην έννοια Quoting).
Κάθε λέξη ανατίθεται διαδοχικά στο varname, και οι εντολές εκτελούνται.
Ορίστε μερικά παραδείγματα που δείχνουν πότε μπορεί να είναι χρήσιμος ο βρόχος for
Εκτέλεσε κάποιες εντολές σε μια ομάδα αρχείων.
# source all the bash library files in the current directory
for file in ./*.bash; do
source "$file"
done
Εκτέλεσε κάποια εντολή σε κάθε μία από τις παραμέτρους ενός script ή μιας συνάρτησης.
for arg in "$@"; do
echo "argument: ${arg}"
done
Εκτέλεσε κάποια εντολή για κάθε λέξη χωρισμένη με κενό διάστημα στην έξοδο μιας εντολής.
for i in $(seq 10); do
echo "${i} squared is $((i * i))"
done
Θα δούμε μερικές προειδοποιήσεις γι' αυτό το στυλ παρακάτω.
for
Η Bash έχει και αριθμητικό βρόχο. Αυτός θα φανεί κάπως γνωστός σε όσους γνωρίζουν άλλες γλώσσες προγραμματισμού.
for ((INITIALIZATION; CONDITION; INCREMENT)); do COMMANDS; done
Οι διπλές παρενθέσεις στη bash αντιπροσωπεύουν ένα αριθμητικό πλαίσιο (θα δούμε περισσότερα για την αριθμητική της bash σε επόμενη έννοια).
Το παραπάνω παράδειγμα με το seq μπορεί να γραφτεί ως εξής
for ((i = 1; i <= 10; i++)); do
echo "${i} squared is $((i * i))"
done
for
Αυτό είναι ένα αντιπρότυπο που θα δεις συχνά: επανάληψη πάνω στην έξοδο του cat.
for line in $(cat some.file); do
do_something_with "$line"
done
Αυτό είναι λάθος για 2 λόγους.
for διατρέχει τις λέξεις του αρχείου, όχι τις γραμμές.Όπως μάθαμε στην έννοια Quoting, ο διαχωρισμός λέξεων μπορεί να ελεγχθεί με τη μεταβλητή IFS και η επέκταση ονομάτων αρχείων μπορεί να απενεργοποιηθεί.
Αλλά αυτή τείνει να είναι μια εύθραυστη λύση.
Το for είναι ο λάθος τρόπος για να διατρέξεις τις γραμμές ενός αρχείου.
Ο ιδιωματικός τρόπος για να διαβάσεις ένα αρχείο είναι με έναν βρόχο while.
while
Χρησιμοποίησε το while για να επαναλαμβάνεις μια σειρά εντολών όσο κάποια συνθήκη είναι αληθής.
while CONDITION_COMMANDS; do COMMANDS; done
Όπως συμβαίνει με το if (όπως μάθαμε στην έννοια Conditionals, δεν υπάρχει ειδική σύνταξη για το CONDITION_COMMANDS.
Η κατάσταση εξόδου της λίστας εντολών θα καθορίσει το "αληθής" ή το "ψευδής".
Η εντολή break βγάζει έξω από τον βρόχο.
Ο έλεγχος συνεχίζει με την εντολή που ακολουθεί τον τερματισμό done του βρόχου.
Η εντολή continue μεταβαίνει στην επόμενη επανάληψη του βρόχου.
Όπως αναφέρθηκε, ένας βρόχος while είναι ο ιδιωματικός τρόπος να διαβάσεις ένα αρχείο.
while IFS= read -r line; do
do_something_with "$line"
done < some.file
Το περιεχόμενο του αρχείου παρέχεται ως είσοδος στον βρόχο με την ανακατεύθυνση <.
Η εντολή read επιστρέφει "αληθής" αν μπορεί να διαβάσει μια πλήρη γραμμή από την είσοδό της.
Όταν η είσοδος καταναλωθεί, ή αν η τελευταία γραμμή τελειώνει χωρίς τελικό χαρακτήρα αλλαγής γραμμής, τότε η read επιστρέφει "ψευδής".
Ο πραγματικά ιδιωματικός τρόπος να διαβάσεις τις γραμμές ενός αρχείου, ακόμα κι αν η τελευταία γραμμή δεν τελειώνει με αλλαγή γραμμής, είναι
while IFS= read -r line || [[ -n "$line" ]]; do ...
Η επιλογή -r λέει στη read να μην αντικαθιστά ακολουθίες με ανάποδη κάθετο: η ανάποδη κάθετος είναι απλώς ένας συνηθισμένος χαρακτήρας.
Το IFS= αναθέτει την κενή συμβολοσειρά στο IFS μόνο για τη διάρκεια της εντολής read.
Αυτό απενεργοποιεί προσωρινά τον διαχωρισμό λέξεων, ώστε να διατηρείται οποιοδήποτε κενό διάστημα στην αρχή ή στο τέλος της γραμμής κειμένου που έρχεται.
untilΗ δομή until επαναλαμβάνει μια σειρά εντολών όσο κάποια συνθήκη είναι ψευδής.
Ο βρόχος επαναλαμβάνεται μέχρι η συνθήκη να γίνει αληθής.
until CONDITION_COMMANDS; do COMMANDS; done
Είναι σπάνιο να χρησιμοποιείς το until.
Είναι πιο συνηθισμένο να χρησιμοποιείς έναν βρόχο "while not".
while ! CONDITION_COMANDS; do ...
Μερικές φορές θέλεις να επαναλαμβάνεις για πάντα. Ορίστε δύο τρόποι να το κάνεις.
ένας βρόχος while με μια συνθήκη που έχει πάντα κατάσταση εξόδου επιτυχίας
while true; do ...
ένας αριθμητικός βρόχος for με κενές εκφράσεις
for ((;;)); do ...
Δεν υπάρχει ρητή δομή do-while, αλλά μπορείς να πετύχεις το ίδιο αποτέλεσμα:
while true; do
COMMANDS
if END_CONDITION; then
break
fi
done