💾 Archived View for magaz.hellug.gr › 29 › 05_bash › index.gmi captured on 2024-08-31 at 12:21:18. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2024-02-05)
-=-=-=-=-=-=-
Μιχάλης Καμπριάνης(mailto:kabrianis@hellug.gr) Σεπ 2000
Το standard shell του Linux είναι το bash, γι αυτό, ας μάθουμε μερικά πράγματα για αυτό.
Το Bash είναι ένα shell που χρησιμοποιείται ως standard στο Linux και υπάρχει διαθέσιμο και σαν πηγαίος κώδικας για να προστεθεί σε οποιoδήποτε Unix θέλετε. Είναι ένα POSIX-compliant shell και βασικά πρόκειται για μια μετεξέλιξη του shell (sh) συνδυάζοντας τα καλύτερα στοιχεία των C-shell (csh) και Korn-shel (ksh).
Το bash υποστηρίζει command-line editing, substitution, filename completion, προχωρημένες δυνατότητες scripting κλπ. Το bash υποστηρίζει βέβαια και wildcharacters ή χαρακτήρες-μπαλαντέρ (? για αντικατάσταση ενός χαρακτήρα και * για αντικατάσταση απεριόριστων χαρακτήρων, [ ] για καθορισμό εύρους τιμών κλπ. Σε κάθε περίπτωση, αυτό το κείμενο δεν μπορεί παρά να κάνει μία απλή εισαγωγή, και για περισσότερες πληροφορίες που θα οδηγούσαν στην πλήρη εκμετάλλευση των δυνατοτήτων του bash, ο αναγνώστης πρέπει να διαβάσει το manual του bash (man bash).
1. Μεταβλητές
2. Ανακατεύθυνση
3. Έξοδος λογικής έκφρασης: test
4. Έλεγχοι ροής
5. Επαναληπτικοί βρόγχοι
Οι μεταβλητές (βασικό στοιχείο σε κάθε πρόγραμμα) στο bash δεν είναι προκαθορισμένου τύπου, μπορεί δηλαδή η ίδια μεταβλητή να έχει αριθμητική τιμή, ή τιμή κειμένου (string) κλπ χωρίς να το προδηλώσουμε πουθενά (αν και για το bash όλες οι μεταβλητές είναι strings, με την χρήση της eval μπορούμε να κάνουμε και αριθμητικές πράξεις αν τα strings αποτελούνται μόνο από αριθμούς). Οι μεταβλητές ορίζονται με απλή τοποθέτηση (assignment, π.χ. var=1) και προσπελαύνονται βάζοντας μπροστά από το όνομά τους το σύμβολο $. Αν η τιμή μίας μεταβλητής εσωκλείεται σε διπλά εισαγωγικά "", τότε το bash αγνοεί οποιαδήποτε κενά βρίσκονται εκεί. Αν δεν τα αγνοούσε, η τιμή της μεταβλητής θα ήταν οτιδήποτε υπάρχει μέχρι το πρώτο κενό. Ότι ήταν μετά το κενό θα θεωρούνταν ως τιμή της δεύτερης μεταβλητής, κάτι το οποίο έχει ιδιαίτερο νόημα για παραμέτρους που δίνονται από την γραμμή εντολών κατά την κλήση του προγράμματος. Αν εσωκλείεται σε ανάποδα μονά εισαγωγικά `, τότε εννοείται ότι πρόκειται περί εντολής, η οποία θα εκτελεστεί και το αποτέλεσμα της εντολής θα αποτελεί την τιμή της μεταβλητής.
Το bash χρησιμοποιεί κάποιες προκαθορισμένες μεταβλητές για τα διάφορα "προγραμματάκια" που μπορούμε να φτιάξουμε. Αυτές είναι οι:
Το bash υποστηρίζει όπως θα ήταν ίσως αναμενόμενο, ανακατεύθυνση των τριών βασικών file descriptors, δηλαδή των standard input, standard output και standard error (αντίστοιχα 0, 1 και 2). Η ανακατεύθυνση της εισόδου γίνεται με το σύμβολο <, και η ανακατεύθυνση εξόδου (και εξόδου λάθους) με το σύμβολο > γράφοντας και τον αριθμό του file descriptor. Δηλαδή η έκφραση command 1> output θα ανακατευθύνει την κανονική έξοδο στο αρχείο output (και είναι ισοδύναμη με την command > output) ενώ η έκφραση command 2> error θα ανακατευθύνει την έξοδο λάθους στο αρχείο error. Για να ανακατευθύνουμε και την κανονική έξοδο, αλλά και την έξοδο λάθους σε ένα αρχείο, μπορούμε να χρησιμοποιήσουμε οποιαδήποτε από τις ακόλουθες εκφράσεις: command &> out, command >& out, command 2>&1 out
Τέλος, το bash υποστηρίζει και piping, να ανακατευθύνει δηλαδή την έξοδο μίας εντολής, στην είσοδο μίας άλλης εντολής, με το σύμβολο |.
Όποτε θέλουμε να ελέγξουμε το αποτέλεσμα μίας λογικής ή αριθμητικής έκφρασης χρησιμοποιούμε τη συνάρτηση test. Η συνάρτηση test επιστρέφει τιμή "αληθής" ή "ψευδής" ανάλογα με το αληθές ή ψευδές της λογικής (ή και αριθμητικής) έκφρασης που ελέγχεται. H συνάρτηση test μπορεί να γραφεί και ώς [ έλεγχος ] . Η έκφραση μπορεί να έχει ένα μόνο στοιχείο και έναν τελεστή (ο οποίος έτσι ονομάζεται unary operator) ή μπορεί να έχει δύο στοιχεία και έναν τελεστή ο οποίος ονομάζεται binary operator. Πιο πολλές πληροφορίες από το manual page της συνάρτησης test το οποίο μπορείτε να δείτε γράφοντας man test
Οι πιο συνηθισμένοι τελεστές:
Η ανωτέρω έκφραση είναι ψευδής γιατί ο (αριθμητικός) τελεστής -eq σημαίνει ισότητα (equal). Άλλοι αριθμητικοί τελεστές είναι οι:
1. -gt ο αριθμός αριστερά είναι μεγαλύτερος από τον αριθμό δεξιά (greater than).
2. -lt ο αριθμός δεξιά είναι μικρότερος από τον αριθμό αριστερά (less than).
3. -ne οι δύο αριθμοί δεν είναι ίσοι (not equal).
4. -ge ο αριθμός αριστερά είναι μεγαλύτερος ή ίσος από τον αριθμό δεξιά (greater or equal).
5. -le ο αριθμός αριστερά είναι μικρότερος ή ίσος από τον αριθμό δεξιά (less or equal).
Η ανωτέρω έκφραση είναι ψευδής γιατί ο (λογικός) τελεστής = σημαίνει ότι τα δύο strings που συγκρίνουμε είναι ίσα (ίδια). Άλλοι λογικοί τελεστές σχετικοί με strings είναι οι:
1. != ο οποίος προφανώς επιστρέφει "αληθές" όταν τα δύο strings που συγκρίνουμε είναι ανόμοια.
2. -z ο οποίος είναι unary operator (συντάσσεται δηλαδή ως εξής: test [ -z string ]) επιστρέφει "αληθές" αν το μήκος του string είναι μηδενικό.
3. -n που είναι και αυτός unary operator (συντάσσεται δηλαδή ως εξής: test [ -n string ]) επιστρέφει "αληθές" αν το μήκος του string δεν είναι μηδενικό.
Η ανωτέρω έκφραση βγαίνει αληθής όταν το αρχείο με όνομα filename υπάρχει. Άλλοι τελεστές ελέγχου της κατάστασης ενός αρχείου είναι οι εξής (όλοι όσοι αναφέρονται εδώ είναι unary operators):
1. -b αν το αρχείο υπάρχει και είναι block device
2. -c αν το αρχείο υπάρχει και είναι character device
3. -d αν το αρχείο υπάρχει και είναι directory
4. -f αν το αρχείο υπάρχει και είναι κανονικό αρχείο
5. -r αν το αρχείο υπάρχει και μπορεί να διαβαστεί
6. -s αν το αρχείο υπάρχει και το μέγεθος του δεν είναι μηδέν
7. -w αν το αρχείο υπάρχει και μπορεί να γραφτεί
8. -x αν το αρχείο υπάρχει και μπορεί να εκτελεστεί
if - then - else
Ένας τρόπος και ο πιο συνηθισμένος ελέγχου ροής ενός προγράμματος είναι ο έλεγχος if-then-else όπου ελέγχουμε το αποτέλεσμα μίας λογικής έκφρασης και ανάλογα με αυτό το αποτέλεσμα καθορίζουμε τι θα κάνει το πρόγραμμα. Προφανώς ο έλεγχος χρησιμοποιεί το αποτέλεσμα της συνάρτησης test για να καθορίσει την ροή. Για παράδειγμα--------------------------------------------------------------------------------
if [ $i -eq 3 ]; then echo 'Number is 3'; elif [ $i -eq 2 ]; then echo 'Number is 2'; else echo 'Number is neither 3 nor 2'; fi
--------------------------------------------------------------------------------
όπου είναι προφανές ότι κάπου στο πρόγραμμά μας έχουμε δώσει τιμή στην παράμετρο $i. Μπορούμε να έχουμε όσα elif θέλουμε, αρκεί στο τέλος να υπάρχει και ένα else. Αν δεν υπάρχει κανέναν elif δεν είναι υποχρεωτικό και το else, είναι όμως σε κάθε περίπτωση υποχρεωτικό το fi.
select
Η συνάρτηση select δουλεύει (και συντάσσεται) όπως η if αλλά δίνει τη δυνατότητα να δημιουργήσουμε menu. Για παράδειγμα--------------------------------------------------------------------------------
select i in a.txt b.txt c.txt; do cat $i; done
--------------------------------------------------------------------------------
Το ανωτέρω παράδειγμα παρουσιάζει στον χρήστη ένα menu με τρεις επιλογές και ανάλογα με την επιλογή του χρήστη, του εμφανίζει το αντίστοιχο αρχείο στην οθόνη.
case
Η συνάρτηση case τέλος, προσομοιάζει στην αντίστοιχη συνάρτηση της C και σαν σύνταξη, αλλά και σαν αποτέλεσμα, και συγκεκριμένα εκτελεί προκαθορισμένες εντολές για προκαθορισμένες τιμές μίας μεταβλητής, έχοντας ταυτόχρονα και μία γενική περίπτωση που δεν εμπίπτει στις υπόλοιπες. Για παράδειγμα--------------------------------------------------------------------------------
case $i in 1 | 3 | 5 | 7 | 9) echo -n "Odd one-digit number";; 0 | 2 | 4 | 6 | 8) echo -n "Even one-digit number";; *) echo -n "It definitely is not a one-digit nummber";; esac
--------------------------------------------------------------------------------
Το ανωτέρω παράδειγμα ελέχει την μεταβλητή $i που υποτίθεται ότι κάπου πιο πριν την έχουμε δώσει, και μας απαντάει αν είναι μονός ή ζυγός μονοψήφιος αριθμός, ή όχι.
for - do
Ο βρόγχος for - do είναι ο πιο συνηθισμένος σε όλες τις γλώσσες προγραμματισμού. Η χρήση του είναι απλούστατη ειδικά στο bash όπου \textbf{δεν μπορούμε να ορίσουμε πεδίο τιμών, αντ' αυτού είμαστε υποχρεωμένοι να ορίζουμε τις τιμές μία μία, ακόμα και αν αυτές είναι κατά κάποια έννοια συνεχόμενες. Ένα παράδειγμα είναι το απλούστατο:--------------------------------------------------------------------------------
for i in 1 3 5 ; do echo $i; done
--------------------------------------------------------------------------------
Το πεδίο τιμών της μεταβλητής $i δεν αποτελείται υποχρεωτικά από αριθμούς αλλά μπορεί να είναι και λέξεις ή γράμματα, ή ακόμα και wildcharacters (* και ?) κάνοντας έτσι αυτό τον βρόγχο ένα πανίσχυρο εργαλείο.
while - do Η συνάρτηση while εκτελεί κάποιες εντολές όσο μία λογική έκφραση είναι αληθής. Το κλασικότερο παράδειγμα είναι η δημιουργία ενός επαναληπτικού βρόγχου, ως εξής:--------------------------------------------------------------------------------
while [ $i -lt 10 ]; do read i; echo $i; done
--------------------------------------------------------------------------------
Προφανώς το παράδειγμα αυτό θα μας εμφανίζει συνέχεια ότι του γράφουμε μέχρι να δώσουμε ένα αριθμό μεγαλύτερο (ή ίσο) του 10. Προσοχή χρειάζεται εδώ, γιατί στο πρόγραμμά μας η μεταβλητή $i πρέπει να έχει τιμή πριν κληθεί η while.