Διαδρομές
/
Bash
Bash
/
Ύλη
/
Σωληνώσεις και λίστες εντολών
Σω

Σωληνώσεις και λίστες εντολών σε Bash

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

Σχετικά με την έννοια Σωληνώσεις και λίστες εντολών

Έχουμε δει πώς να γράφουμε απλές εντολές, όπου μια εντολή ακολουθείται από ορίσματα. Τώρα θα δούμε πώς να φτιάχνουμε πιο σύνθετες εντολές, συνθέτοντας απλές εντολές.

Είσοδος και έξοδος

Πριν ξεκινήσουμε, μια γρήγορη εισαγωγή στην είσοδο/έξοδο.

Οι διεργασίες έχουν "τυποποιημένα κανάλια εισόδου/εξόδου".

  • Μια διεργασία μπορεί να καταναλώνει είσοδο από το "stdin".
  • Μια διεργασία μπορεί να εκπέμπει έξοδο στο "stdout".
  • Μια διεργασία μπορεί να εκπέμπει έξοδο σφάλματος στο "stderr".

Η εντολή tr είναι ένα πολύ καθαρό παράδειγμα αυτού. Το μόνο που κάνει είναι να διαβάζει κείμενο από την είσοδό της, να εκτελεί μεταγραφές χαρακτήρων και να εκτυπώνει το κείμενο που προκύπτει στην έξοδό της.

Θα δούμε περισσότερα για τον χειρισμό των καναλιών "stdio" αργότερα στο πρόγραμμα σπουδών.

Σωληνώσεις

Αυτό είναι ένα από τα πιο δυνατά σημεία του προγραμματισμού στο κέλυφος. Οι σωληνώσεις σου επιτρέπουν να δημιουργείς περίπλοκους μετασχηματισμούς σε μια ροή κειμένου.

Για να παράγεις μια ταξινομημένη λίστα χρηστών:

cat /etc/passwd | cut -d : -f 1 | sort

Το σύμβολο του σωλήνα (|) συνδέει την έξοδο μιας εντολής με την είσοδο μιας άλλης. Το cut διαβάζει την έξοδο του cat και το sort διαβάζει την έξοδο του cut.

Advanced
  • Από προεπιλογή, κάθε εντολή σε μια σωλήνωση εκτελείται σε ξεχωριστό υποκέλυφος. (Ένα υποκέλυφος είναι μια θυγατρική διεργασία που αποτελεί αντίγραφο του κελύφους που εκτελείται εκείνη τη στιγμή.)

  • Υπάρχει ένα κόστος επιδόσεων όταν εκτελείς σωληνώσεις. Αν βρεθείς με μακροσκελείς σωληνώσεις από παρόμοιες εντολές, σκέψου να τις συνδυάσεις σε μία εντολή. Για παράδειγμα, οι σωληνώσεις που χρησιμοποιούν πολλαπλές εμφανίσεις των grep, cut, sed, awk και tr μπορούν συνήθως να συνδυαστούν σε μία εντολή awk για λόγους αποδοτικότητας.

  • Η κατάσταση εξόδου μιας σωλήνωσης είναι η κατάσταση εξόδου της τελευταίας εντολής της σωλήνωσης. Αυτό σημαίνει ότι αν κάποια προηγούμενη εντολή απέτυχε αλλά η τελευταία πέτυχε, η κατάσταση εξόδου ολόκληρης της σωλήνωσης είναι μηδέν.

    Υπάρχει μια ρύθμιση του κελύφους που μπορεί να το αλλάξει αυτό· αν η ρύθμιση "pipefail" είναι ενεργοποιημένη (με set -o pipefail), τότε η κατάσταση εξόδου της σωλήνωσης θα είναι:

    • μηδέν αν όλες οι εντολές πετύχουν, αλλιώς
    • η τελευταία μη μηδενική κατάσταση εξόδου των εντολών της σωλήνωσης.

Λίστες εντολών

Μια λίστα εντολών είναι μια ακολουθία σωληνώσεων που χωρίζονται με ; (ή αλλαγή γραμμής), && ή ||.

  • Το A; B είναι μια λίστα εντολών όπου το B εκτελείται αφού ολοκληρωθεί το A.
  • Το A && B, όπου το B εκτελείται μόνο αν το A πετύχει (βγει με κατάσταση μηδέν).
  • Το A || B, όπου το B εκτελείται μόνο αν το A αποτύχει (βγει με μη μηδενική κατάσταση).

Η κατάσταση εξόδου μιας λίστας εντολών είναι η κατάσταση εξόδου της τελευταίας εντολής που εκτελέστηκε.

Οι τελεστές && και || μπορούν να αλυσοδεθούν, ώστε η επόμενη εντολή να εκτελεστεί υπό συνθήκη με βάση την κατάσταση των προηγούμενων εντολών. Για παράδειγμα

A && B && C && D || E
  • Το B εκτελείται αν το A πετύχει,
  • Το C εκτελείται αν τα A και B πετύχουν,
  • Το D εκτελείται αν τα A και B και C πετύχουν,
  • Το E εκτελείται αν οποιοδήποτε από τα A, B, C ή D αποτύχει.
Caution

Χρησιμοποίησε αυτούς τους λογικούς τελεστές με φειδώ. Μπορούν γρήγορα να οδηγήσουν σε δυσανάγνωστο κώδικα ή σε λογική που είναι δύσκολο να κατανοήσεις.

Για παράδειγμα, μπορεί να νομίζεις ότι αυτά είναι τα ίδια:

if A; then B; else C; fi
A && B || C

Η διαφορά είναι: πότε εκτελείται το C;

  • Στο πρώτο απόσπασμα (την εντολή if), το C θα εκτελεστεί μόνο αν αποτύχει το A.
  • Στο δεύτερο απόσπασμα, το C θα εκτελεστεί αν αποτύχει το A ή αν το A πετύχει αλλά το B αποτύχει!

Χρήσεις των λιστών εντολών

Να μερικά παραδείγματα όπου οι λίστες εντολών μπορούν να απλοποιήσουν τον κώδικα.

Ανάγνωση ομάδων γραμμών από ένα αρχείο

Ας υποθέσουμε ότι έχεις ένα αρχείο δεδομένων που περιέχει δεδομένα για τρίγωνα, και ότι κάθε τρίγωνο παριστάνεται από τρεις ξεχωριστές γραμμές που περιέχουν τις πλευρές του τριγώνου.

$ cat triangle.dat
3
4
5
9
12
14

Μπορείς να χρησιμοποιήσεις έναν βρόχο while όπου η συνθήκη είναι τρεις ξεχωριστές εντολές read:

while read a && read b && read c; do
    if is_pythagorean "$a" "$b" "$c"; then
        echo "$a:$b:$c is pythagorean"
    else
        echo "$a:$b:$c is not pythagorean"
    fi
done < triangle.dat

Αν υποθέσουμε ότι το is_pythagorean είναι μια εντολή που προσδιορίζει αν οι τρεις πλευρές ικανοποιούν την πυθαγόρεια εξίσωση, η έξοδος θα ήταν:

3:4:5 is pythagorean
9:12:14 is not pythagorean
Ισχυρισμοί

Πολλές γλώσσες προγραμματισμού έχουν μια μορφή ισχυρισμού, όπου πετιέται μια εξαίρεση αν αποτύχει κάποια συνθήκη

assert(user == "Administrator", "wrong user");

Μπορούμε να χρησιμοποιήσουμε έναν τελεστή OR στη Bash για να προσομοιώσουμε αυτή τη συνάρτηση:

die () { # a little convenience function
    echo "$*" >&2
    exit 1
}

[[ $user == "Administrator" ]] || die "wrong user"
[[ $password == "secret!" ]]   || die "incorrect password"

Θέματα στυλ

Οι μεγάλες λίστες εντολών γίνονται γρήγορα δυσανάγνωστες. Η άφθονη χρήση αλλαγών γραμμής μπορεί να βοηθήσει πολύ.

Δες αυτό το παράδειγμα, όπου μια λέξη προστίθεται σε έναν πίνακα αν πληρούνται δύο συνθήκες.

[[ "$word" != "$topic" ]] && [[ "$key" == "$(sorted "$topic")" ]] && anagrams+=("$candidate")

Η Bash σου επιτρέπει να προσθέσεις μια αλλαγή γραμμής μετά από έναν σωλήνα ή έναν λογικό τελεστή.

[[ "$word" != "$topic" ]] &&
[[ "$key" == "$(sorted "$topic")" ]] &&
anagrams+=("$candidate")

Ωστόσο, ο τελεστής μπορεί εύκολα να περάσει απαρατήρητος στο τέλος της γραμμής. Χρησιμοποιώντας μια συνέχεια γραμμής, μπορείς να βάλεις πρώτα τον τελεστή, κάτι που κάνει πιο φανερό ότι η λίστα συνεχίζεται:

[[ "$word" != "$topic" ]] \
&& [[ "$key" == "$(sorted "$topic")" ]] \
&& anagrams+=("$candidate")
Note

Μια συνέχεια γραμμής είναι η ακολουθία δύο χαρακτήρων "ανάποδη κάθετος" και "αλλαγή γραμμής" (\ + \n). Όταν η Bash βλέπει αυτή την ακολουθία, την αφαιρεί απλώς από τον κώδικα, συνεχίζοντας έτσι την τρέχουσα γραμμή με την επόμενη γραμμή. Πρόσεξε να μην αφήσεις κενά ανάμεσα στην ανάποδη κάθετο και στην αλλαγή γραμμής.

Ας δούμε άλλο ένα παράδειγμα

printf "%s\n" "${numbers[@]}" | bc --mathlib | sort --general-numeric-sort

ή

printf "%s\n" "${numbers[@]}" \
| bc --mathlib \
| sort --general-numeric-sort
Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα