Διαδρομές
/
Bash
Bash
/
Ύλη
/
Συναρτήσεις
Συ

Συναρτήσεις σε Bash

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

Σχετικά με την έννοια Συναρτήσεις

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

Ορισμός συνάρτησης

Ορίζεις μια συνάρτηση ως εξής:

my_function () {
    COMMANDS
}

Το κενό ζεύγος παρενθέσεων δηλώνει απλώς ότι ορίζεις μια συνάρτηση. Μέσα τους δεν μπαίνει τίποτα.

Παράμετροι συνάρτησης

Οι συναρτήσεις, αφού οριστούν, συμπεριφέρονται σαν οποιαδήποτε άλλη εντολή (ενσωματωμένη ή όχι). Όπως με κάθε εντολή, μπορείς να δώσεις ορίσματα στις συναρτήσεις σου. Μέσα στη συνάρτηση, προσπελαύνεις τα ορίσματα μέσω των θεσιακών παραμέτρων, $1, $2, κ.λπ. (Θυμήσου, μάθαμε για τις θεσιακές παραμέτρους στην έννοια Μεταβλητές.)

Advanced

Η ειδική παράμετρος $0 δεν αλλάζει μέσα σε μια συνάρτηση· παραμένει το όνομα του σεναρίου που εκτελείται. Η συνάρτηση που εκτελείται τη δεδομένη στιγμή μπορεί να προσπελάσει το όνομά της με τη μεταβλητή $FUNCNAME.

Δες την ενότητα 3.4.2 Special Parameters στο εγχειρίδιο.

Μεταβλητές

Μπορείς να ορίσεις μεταβλητές μέσα σε μια συνάρτηση. Αν δηλώσεις τις μεταβλητές με την εντολή local, η εμβέλεια της μεταβλητής περιορίζεται στην τρέχουσα συνάρτηση (και σε όποιες συναρτήσεις καλεί αυτή). Διαφορετικά, η μεταβλητή τοποθετείται στην καθολική εμβέλεια.

Οι τοπικές μεταβλητές μπορούν να έχουν το ίδιο όνομα με μια καθολική μεταβλητή. Σε αυτή την περίπτωση, η τοπική μεταβλητή "επισκιάζει" την καθολική μεταβλητή. Για παράδειγμα, μια τοπική μεταβλητή που δηλώνεται μέσα σε μια συνάρτηση κρύβει μια καθολική μεταβλητή με το ίδιο όνομα: οι αναφορές και οι εκχωρήσεις αφορούν την τοπική μεταβλητή, αφήνοντας την καθολική μεταβλητή αμετάβλητη. Όταν η συνάρτηση επιστρέψει, η καθολική μεταβλητή γίνεται και πάλι ορατή.

x=5

myfunc () {
    local x=100
    echo "in my function, $x == 100"
}

echo "in the global scope, $x == 5"

myfunc

echo "back in the global scope, $x == 5"

Αυτό τυπώνει

in the global scope, 5 == 5
in my function, 100 == 100
back in the global scope, 5 == 5

Μέσα σε μια συνάρτηση, μπορείς να προσπελάσεις μεταβλητές από την εμβέλεια αυτού που καλεί. Αυτό σημαίνει ότι μπορείς να χρησιμοποιήσεις καθολικές μεταβλητές, καθώς και τοπικές μεταβλητές που δηλώθηκαν στον καλούντα (ή σε κάποια συνάρτηση που καλεί τον καλούντα).

Advanced

Τεχνικά, το "καθολικό" δεν είναι η σωστή λέξη. Για να επεκτείνει μια μεταβλητή μέσα σε μια συνάρτηση, το Bash ανεβαίνει τη στοίβα κλήσεων, μέχρι την καθολική εμβέλεια, για να βρει μια συνάρτηση όπου έχει δηλωθεί αυτό το όνομα μεταβλητής.

Αυτό το παράδειγμα είναι προσαρμοσμένο από την ενότητα Shell Functions του εγχειριδίου:

func1() {
    local var='func1 local'
    func2
}

func2() {
    echo "In func2, var = $var"
}

var=global
func1
func2

Η έξοδος είναι:

In func2, var = func1 local
In func2, var = global

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

Advanced

Η στοίβα κλήσεων μπορεί να εξεταστεί χρησιμοποιώντας τη μεταβλητή πίνακα FUNCNAME.

Τιμές επιστροφής

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

Μπορείς να χρησιμοποιήσεις την εντολή return για να επιστρέψεις από μια συνάρτηση με συγκεκριμένη κατάσταση εξόδου.

check_password () {
    if [[ $1 == "secret" ]]; then
        return 0
    else
        return 1
    fi
}

read -sp "Enter your password: " pass

if check_password "$pass"; then
    echo "Correct!"
else
    echo "Wrong password."
fi

Η χρήση του return χωρίς ορίσματα επιστρέφει την κατάσταση της τελευταίας εντολής που εκτελέστηκε.

Note

Σημείωσε ότι η συνάρτηση check_password μπορεί να απλοποιηθεί ως εξής:

check_password () { [[ $1 == "secret" ]]; }
  1. Η δομή συνθήκης [[...]] έχει κατάσταση εξόδου: 0 για "αληθής", 1 για "ψευδής".
  2. Η δομή ομαδοποίησης {...} πρέπει να έχει είτε μια αλλαγή γραμμής είτε ένα semicolon πριν το τελικό άγκιστρο.

Έξοδος συνάρτησης

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

Η συνάρτηση σου μπορεί να τυπώσει στην τυπική έξοδο. Χρησιμοποίησε τη γνωστή υποκατάσταση εντολής για να την καταγράψεις:

d6 () { echo "$(( 1 + RANDOM % 6 ))"; }

die=$( d6 )
echo "You rolled a $die."

Χρήση και της εξόδου και της κατάστασης

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

roll () {
    local n=$1
    if (( 4 <= n && n <= 20 )); then
        echo "$(( 1 + RANDOM % n ))"  # exit status is 0
    else
        return 1
    fi
}

read -p "How many faces does your die have? " faces
if die=$( roll "$faces" ); then
    echo "You rolled a $die."
else
    echo "I can't roll a die with $faces faces."
fi

Αναδρομή

Οι συναρτήσεις μπορούν να καλέσουν τον εαυτό τους αναδρομικά. Από προεπιλογή, δεν υπάρχει όριο στο βάθος της αναδρομής.

Ένα παράδειγμα:

fibonacci() {
    local n=$1
    if (( n <= 1 )); then
        echo "1"
    else
        local a=$(fibonacci "$(( n - 1 ))")
        local b=$(fibonacci "$(( n - 2 ))")
        echo "$(( a + b ))"
    fi
}

for i in {1..10}; do fibonacci "$i"; done
# => 1
# => 2
# => 3
# => 5
# => 8
# => 13
# => 21
# => 34
# => 55
# => 89
Advanced

Το βάθος της αναδρομής μπορεί να ελεγχθεί με τη μεταβλητή FUNCNEST.

bash -c '
    recur() {
        echo $1
        recur $(($1 + 1))
    }
    FUNCNEST=5
    recur 1
'
1
2
3
4
5
environment: line 1: recur: maximum function nesting level exceeded (5)
Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα