Διαδρομές
/
Bash
Bash
/
Ύλη
/
Επανάληψη
Επ

Επανάληψη σε Bash

{one: "1 άσκηση", other: "%{count} ασκήσεις"}

Σχετικά με την έννοια Επανάληψη

Η 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

Μη διαβάζεις γραμμές με for.

Αυτό είναι ένα αντιπρότυπο που θα δεις συχνά: επανάληψη πάνω στην έξοδο του cat.

for line in $(cat some.file); do 
    do_something_with "$line"
done

Αυτό είναι λάθος για 2 λόγους.

  1. Η αντικατάσταση εντολής δεν περικλείεται σε εισαγωγικά, οπότε υπόκειται σε διαχωρισμό λέξεων. Ο διαχωρισμός λέξεων, από προεπιλογή, χωρίζει σε κενά διαστήματα, όχι μόνο σε αλλαγές γραμμής. Αυτός ο βρόχος for διατρέχει τις λέξεις του αρχείου, όχι τις γραμμές.
  2. Η αντικατάσταση εντολής δεν περικλείεται σε εισαγωγικά, οπότε υπόκειται σε επέκταση ονομάτων αρχείων. Κάθε λέξη του αρχείου θα αντιστοιχιστεί ως μοτίβο glob.

Όπως μάθαμε στην έννοια 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 ...

Ατέρμονοι βρόχοι

Μερικές φορές θέλεις να επαναλαμβάνεις για πάντα. Ορίστε δύο τρόποι να το κάνεις.

  1. ένας βρόχος while με μια συνθήκη που έχει πάντα κατάσταση εξόδου επιτυχίας

    while true; do ...
    
  2. ένας αριθμητικός βρόχος for με κενές εκφράσεις

    for ((;;)); do ...
    

do-while

Δεν υπάρχει ρητή δομή do-while, αλλά μπορείς να πετύχεις το ίδιο αποτέλεσμα:

while true; do
    COMMANDS

    if END_CONDITION; then
        break
    fi
done
Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα