Học bằng cách đọc theo thứ tự

Hàm — Gom đoạn xử lý lặp lại vào một chỗ

Bài viết này là một phần của Khóa học Linux, giúp bạn thành thạo từ đầu những kỹ năng Linux thực tiễn, từ các lệnh cơ bản đến lập trình shell script.
Định nghĩa logic bằng name() { ... }, nhận tham số qua $1, giữ biến cục bộ trong hàm bằng local, và rẽ nhánh theo thành công bằng return và $? để tái sử dụng cùng một logic kiểm tra — được minh họa và thực hành trong terminal trên trình duyệt.

Đặt tên cho một khối logic — định nghĩa hàm và tham số

Thay vì viết cùng một logic lặp đi lặp lại, bạn có thể gói nó vào một hàm và gọi nó bằng tên.

Định nghĩa một hàm bằng name() { ... }, và đặt phần thân giữa {}.

Sau khi định nghĩa, chỉ cần viết name để chạy logic đó.

Cách này chia một script dài thành các đơn vị có ý nghĩa, và bạn chỉ phải sửa ở một chỗ.

Để truyền giá trị vào một hàm, hãy thêm tham số sau tên khi bạn gọi nó, ví dụ name foo bar.

Bên trong hàm, $1 là tham số thứ nhất và $2 là tham số thứ hai (cùng cách viết với các tham số vị trí của chính script).

Bao một tham số trong dấu nháy kép như "$1", và ngay cả một giá trị có khoảng trắng cũng được xem như một tham số duy nhất.

greet() {                        # định nghĩa một hàm
  echo "hello, $1"
}
greet alice                      # hello, alice
greet bob                        # hello, bob
Cách lời gọi ánh xạ tới tham số
greet alice bob$1 = alice$2 = bobdùng $1 $2 trong thânthứ 1thứ 2bên trong greet
Các giá trị trong greet alice bob đi vào $1$2, và phần thân hàm dùng chúng để làm việc.
Cú phápÝ nghĩaVí dụ
name() { … }Định nghĩa một hàmgreet() { echo "hi $1"; }
name argsGọi một hàmgreet alice
$1Tham chiếu tham số thứ nhất bên trong hàmecho "name=$1"
$2Tham chiếu tham số thứ hai bên trong hàmecho "port=$2"

Tạo một script tiện ích gom logic kiểm tra đầu vào vào một hàm và tái sử dụng nó.

① Mở validate.sh bằng vi validate.sh, nhấn i để vào chế độ chèn, và viết #!/bin/sh ở dòng đầu tiên.

② Định nghĩa một hàm nhận một giá trị, kiểm tra xem nó có rỗng hay không, và in ra kết quả. Tham chiếu tham số bằng $1 bên trong hàm.

③ Gọi hàm vài lần với các giá trị khác nhau.

④ Nhấn Esc và lưu bằng :wq, sau đó thêm quyền thực thi và chạy script để kiểm tra kết quả của mỗi lần gọi.

⑤ Nếu bạn không chắc cần viết gì, bạn có thể sao chép phần thân từ bảng đáp án và dán vào chế độ chèn của vi. (Chạy đúng thì phần giải thích sẽ hiện ra.)

Linux console
0 / 3 đã hoàn thành
Loading Linux Terminal...

Biến chỉ tồn tại bên trong một hàm — local

Khi bạn khai báo local v=... bên trong một hàm, biến đó chỉ có hiệu lực bên trong hàm và biến mất khi hàm kết thúc.

Không có local, bạn cũng ghi đè lên một biến cùng tên ở bên ngoài hàm, điều này gây ra những tác dụng phụ không mong muốn.

Để tái sử dụng một hàm an toàn như một thành phần, hãy làm cho các biến làm việc mà nó dùng bên trong thành local.

msg="outer"
show() {
  local msg="inner"            # biến chỉ tồn tại trong hàm
  echo "in func: $msg"
}
show                           # in func: inner
echo "outside: $msg"           # outside: outer (bên ngoài không đổi)
Phạm vi mà local nhìn thấy được
msg=outerecho "$msg"in ra outerlocal msg=innerecho "$msg"in ra innertoàn bộ scripttrong hàm (local)
Một biến thông thường nhìn thấy được ở mọi nơi, còn một biến local chỉ có hiệu lực bên trong hàm. Dù cùng tên, giá trị bên ngoài cũng không thay đổi.
Cú phápÝ nghĩaVí dụ
local v=…Tạo một biến chỉ có hiệu lực bên trong hàmlocal step=1
v=…Một biến có hiệu lực trên toàn bộ scriptstatus=ready

Tạo một script làm cho một biến làm việc thành local và xác nhận nó không ảnh hưởng đến bên ngoài.

① Mở scope.sh bằng vi scope.sh, nhấn i để vào chế độ chèn, và viết #!/bin/sh ở dòng đầu tiên.

② Đặt một biến ở bên ngoài, rồi định nghĩa một hàm khai báo một biến cùng tên bằng local và gán cho nó một giá trị khác.

③ Sau khi gọi hàm, in biến bên ngoài để xác nhận giá trị của nó không thay đổi.

④ Nhấn Esc và lưu bằng :wq, sau đó thêm quyền thực thi và chạy script.

⑤ Nếu bạn không chắc cần viết gì, bạn có thể sao chép phần thân từ bảng đáp án và dán vào chế độ chèn của vi.

Linux console
0 / 3 đã hoàn thành
Loading Linux Terminal...

Trả về thành công hay thất bại — return và $?

Một hàm có thể trả về một mã thoát bằng return N.

Theo quy ước 0 nghĩa là thành công và bất kỳ giá trị nào khác 0 nghĩa là thất bại, và ngay sau khi gọi nó bạn có thể kiểm tra giá trị đó bằng $?.

Rẽ nhánh trực tiếp theo thành công của một hàm như if check "$x"; then ... giúp luồng kiểm tra và xử lý dễ đọc hơn.

is_num() {
  case "$1" in
    *[!0-9]*|"") return 1 ;;     # thất bại nếu chứa ký tự không phải số hoặc rỗng
    *) return 0 ;;
  esac
}
is_num 12; echo "12 -> $?"       # 12 -> 0
is_num abc; echo "abc -> $?"     # abc -> 1
Từ return đến rẽ nhánh theo $?
is_num "$1"return 0return 1nhánh thành côngnhánh thất bạilà sốkhông phải số$? = 0 → thành công$? = 1 → thất bại
Giá trị từ return đi vào $?, và if rẽ nhánh xem 0 là thành công và khác không là thất bại.
Cú phápÝ nghĩaVí dụ
return 0Thoát hàm với kết quả thành côngis_num 12; # success
return 1Thoát hàm với kết quả thất bạiis_num abc; # failure
$?Kiểm tra giá trị trả về của hàm trước đóis_num 12; echo $?
if name x; then …Rẽ nhánh trực tiếp theo giá trị trả vềif is_num "$v"; then …; fi

Tạo một hàm quyết định xem một giá trị có phải là số hay không, và một script rẽ nhánh theo giá trị trả về của nó.

① Mở isnum.sh bằng vi isnum.sh, nhấn i để vào chế độ chèn, và viết #!/bin/sh ở dòng đầu tiên.

② Định nghĩa một hàm kiểm tra xem giá trị nhận được có chỉ gồm chữ số hay không, trả về return 0 nếu là số và return 1 nếu không.

③ Đặt hàm đó trực tiếp vào điều kiện của một if và in ra thông báo thành công hoặc thất bại cho vài đầu vào.

④ Nhấn Esc và lưu bằng :wq, sau đó thêm quyền thực thi và chạy script để kiểm tra kết quả.

⑤ Nếu bạn không chắc cần viết gì, bạn có thể sao chép phần thân từ bảng đáp án và dán vào chế độ chèn của vi.

Linux console
0 / 3 đã hoàn thành
Loading Linux Terminal...
QUIZ

Kiểm tra kiến thức

Hãy trả lời từng câu hỏi một.

Câu 1Cách viết nào tham chiếu tham số thứ nhất bên trong một hàm shell?

Câu 2Phạm vi của một biến được khai báo bằng local là gì?

Câu 3Cách nào kiểm tra giá trị trả về của hàm gần nhất?