Bài viết trước của tôi về “Hiểu và viết các hàm trong Shell Scripts” có thể đã cho bạn một ý tưởng cơ bản về cách viết các hàm trong shell script. Bây giờ đã đến lúc đi sâu hơn vào các tính năng chức năng như việc sử dụng các biến cục bộ và đệ quy.
Biến cục bộ
Điều gì làm cho một biến cục bộ? Nó phụ thuộc vào khối cụ thể mà biến được khai báo. Một biến được khai báo là cục bộ sẽ có thể truy cập được từ khối mã đó khi nó xuất hiện, tức là phạm vi của nó là cục bộ. Để giải thích điều này, chúng ta hãy xem xét một ví dụ dưới đây.
#!/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
Khi thực thi tập lệnh trên, đầu ra sẽ là.
i outside func = j outside func = i from func = 10 j from func = 20 i outside func = j outside func = 20
Điều này là do hàm func vẫn chưa được gọi trong khi 2 đầu tiên các câu lệnh echo đã được thực thi. Sau khi gọi hàm func 2 câu lệnh echo giống nhau tạo ra một kết quả khác. Bây giờ là biến j , được khai báo bên trong func và không cục bộ, có thể được truy cập sau đó.
Do đó, giá trị cho j trở thành 20 . Còn về biến cục bộ i ? Vì phạm vi của nó nằm trong hàm func , giá trị 10 không thể được truy cập từ bên ngoài. Lưu ý rằng biến j thường được khai báo bên trong func là toàn cầu theo mặc định.
Bây giờ bạn đã quen với các biến cục bộ và cách sử dụng chúng bên trong các khối chức năng. Chúng ta hãy chuyển sang phần thú vị nhất dưới các hàm, phần đệ quy.
Đệ quy là gì?
Một hàm gọi chính nó thường được gọi là thủ tục đệ quy. Hoặc nó có thể được định nghĩa là thể hiện một thuật toán bằng cách sử dụng một phiên bản đơn giản hơn của cùng một thuật toán đó. Hãy xem xét ví dụ về tìm giai thừa của một số. Chúng tôi biết rằng n! =1 x 2 x 3 x… x (n-1) x n . Do đó, chúng ta có thể viết một quan hệ lặp lại là:
n! = (n-1)! x n
Vì vậy, thật dễ dàng để chúng tôi gọi đệ quy cùng một hàm và sử dụng giá trị trả về từ mỗi lần gọi để nhân với kết quả trước đó, tức là
5! = 4! x 5 4! = 3! x 4 3! = 2! x 3 2! = 1! x 2 1! = 0! x 1
Đệ quy sử dụng Biến cục bộ
Ở đây chúng tôi cố gắng viết một tập lệnh để tìm giai thừa của một số bằng cách sử dụng các biến cục bộ và đệ quy.
#!/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 là một biến cục bộ được sử dụng để lưu trữ từng n-1 giá trị trên mỗi cuộc gọi. Ở đây điều kiện cơ sở kiểm tra xem số có bằng 0 hay không (vì 0! =1 và giai thừa không được xác định cho số âm). Khi đến điều kiện cơ sở này, nó trả về giá trị 1 cho người gọi của nó. Bây giờ num =1 và ret =1 x 1 .
Ngay lúc này, nó trả về 1 cho người gọi của nó. Bây giờ num =2 và ret =2 x 1 và như thế. Cuối cùng khi num =5 giá trị trả về sẽ là 24 và kết quả cuối cùng là ret =5 x 24 . Kết quả cuối cùng 120 được chuyển xuống câu lệnh người gọi ban đầu và được hiển thị.
Có một vấn đề trong tập lệnh trên. Như tôi đã giải thích trong bài trước, các hàm không thể trả về số nguyên lớn. Vì vậy, người dùng phải tìm giải pháp cho vấn đề trên.
Q. Chúng ta có thể thực hiện đệ quy mà không sử dụng các biến cục bộ không? Câu trả lời là Có .
Đệ quy không có biến cục bộ
Xem ví dụ sau để hiển thị chuỗi Fibonacci sử dụng đệ quy. Mối quan hệ lặp lại cơ bản là:
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
Không có biến cục bộ nào được sử dụng trong tập lệnh trên. Tôi hy vọng bạn có thể hiểu quy trình của tập lệnh trong quá trình thực thi.
Đây là giá trị 15 đại diện cho số thuật ngữ trong chuỗi Fibonacci được hiển thị. Bạn có nhận thấy bất cứ điều gì đặc biệt liên quan đến việc thực thi tập lệnh trên. Phải mất một lúc, phải không? Đệ quy trong một tập lệnh chậm hơn đệ quy trong các ngôn ngữ lập trình như C .
Với bài viết này, tôi dự định kết thúc các phần chức năng trong kịch bản shell. Luôn cập nhật với Tecmint để có các bài viết sắp tới về mảng và nhiều hơn nữa…