Πιο βαθύτερα στις πολυπλοκότητες λειτουργιών με το Shell Scripting – Μέρος VII


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

Τοπικές μεταβλητές

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

#!/bin/bash 

func( ) { 
	local i=10 
	j=20 
	echo "i from func = $i" 
	echo "j from func = $j" 
} 

echo "i outside func = $i" 
echo "j outside func = $j" 

func 

echo "i outside func = $i" 
echo "j outside func = $j" 

exit 0

Κατά την εκτέλεση της παραπάνω δέσμης ενεργειών η έξοδος θα είναι.

i outside func = 
j outside func = 
i from func = 10 
j from func = 20 
i outside func = 
j outside func = 20

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

Έτσι, η τιμή για το j γίνεται 20. Τι γίνεται με την τοπική μεταβλητή i; Δεδομένου ότι το εύρος της ήταν εντός της συνάρτησης func, η τιμή 10 δεν ήταν προσβάσιμη από έξω. Σημειώστε ότι η μεταβλητή j που συνήθως δηλώνεται στο func είναι καθολική από προεπιλογή.

Τώρα είστε εξοικειωμένοι με τις τοπικές μεταβλητές και τον τρόπο χρήσης τους μέσα σε μπλοκ συναρτήσεων. Ας προχωρήσουμε στην πιο ενδιαφέρουσα ενότητα των συναρτήσεων, την αναδρομή.

Τι είναι η Αναδρομή;

Μια συνάρτηση που καλεί τον εαυτό της ονομάζεται γενικά ως διαδικασία αναδρομής. Ή μπορεί να οριστεί ότι εκφράζει έναν αλγόριθμο χρησιμοποιώντας μια απλούστερη έκδοση του ίδιου αλγορίθμου. Εξετάστε το παράδειγμα εύρεσης παραγοντικού ενός αριθμού. Ξέρουμε ότι τον!=1 x 2 x 3 x … x (n-1) x n. Έτσι μπορούμε να γράψουμε μια σχέση επανάληψης ως:

n! = (n-1)! x n

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

5! = 4! x 5
4! = 3! x 4
3! = 2! x 3
2! = 1! x 2
1! = 0! x 1

Αναδρομή με χρήση τοπικών μεταβλητών

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

#!/bin/bash 

fact( ) { 
	local num=$1 
	if [ $num -eq 0 ]; then 
		ret=1 
	else 
		temp=$((num-1)) 
		fact $temp 
		ret=$((num*$?)) 
	fi 
	return $ret 
} 

fact 5 

echo "Factorial of 5 = $?" 

exit 0

Το num είναι μια τοπική μεταβλητή που χρησιμοποιείται για την αποθήκευση κάθε τιμής n-1 σε κάθε κλήση. Εδώ η βασική συνθήκη ελέγχει αν ο αριθμός είναι ίσος με μηδέν ή όχι (αφού 0!=1 και το παραγοντικό δεν ορίζεται για αρνητικούς αριθμούς). Μόλις φτάσει σε αυτήν τη βασική συνθήκη, επιστρέφει την τιμή 1 στον καλούντα. Τώρα num=1 και ret=1 x 1.

Αυτή τη στιγμή επιστρέφει 1 στον καλούντα. Τώρα num=2 και ret=2 x 1 και ούτω καθεξής. Τέλος, όταν num=5 επιστρέφεται η τιμή 24 και το τελικό αποτέλεσμα είναι ret=5 x 24. Το τελικό αποτέλεσμα 120 μεταβιβάζεται στην αρχική δήλωση καλούντος και εμφανίζεται.

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

Ε. Μπορούμε να εκτελέσουμε αναδρομή χωρίς τη χρήση τοπικών μεταβλητών; Η απάντηση είναι Ναι.

Αναδρομή χωρίς τοπικές μεταβλητές

Δείτε το παρακάτω παράδειγμα για την εμφάνιση της σειράς Fibonacci χρησιμοποιώντας αναδρομή. Η βασική σχέση υποτροπής είναι:

fib(0) = 0 
fib(1) = 1 
else 
	fib(n) = fib(n-1) + fib(n-2)

Fibonacci series using recursion

#!/bin/bash 

fib( ) { 
	a=$1 
	if [ $a -lt 2 ]; then 
		echo $a 
	else 
		((--a)) 
		b=$(fib $a) 

		((--a)) 
		c=$(fib $a) 

		echo $((b+c)) 
	fi 
} 

for i in $(seq 0 15) 
do 
	out=$(fib $i) 
	echo $out 
done 

exit 0

Δεν χρησιμοποιούνται τοπικές μεταβλητές στο παραπάνω σενάριο. Ελπίζω να καταλάβετε τη ροή του σεναρίου κατά την εκτέλεση.

Εδώ η τιμή 15 αντιπροσωπεύει τον αριθμό των όρων στη σειρά Fibonacci που θα εμφανιστούν. Παρατηρήσατε κάτι ιδιαίτερο σχετικά με την εκτέλεση του παραπάνω σεναρίου. Παίρνει λίγο χρόνο, έτσι δεν είναι; Η αναδρομή σε ένα σενάριο είναι πιο αργή από μια αναδρομή σε γλώσσες προγραμματισμού όπως η C.

Με αυτό το άρθρο, σκοπεύω να ολοκληρώσω το τμήμα συναρτήσεων στο σενάριο κελύφους. Μείνετε ενημερωμένοι με το Tecmint για να έχετε τα επερχόμενα άρθρα σχετικά με τους πίνακες και πολλά άλλα…