Các câu lệnh Bash case rất mạnh mẽ nhưng dễ viết. Khi bạn truy cập lại một tập lệnh Linux cũ, bạn sẽ rất vui vì bạn đã sử dụng case
tuyên bố thay vì dài if-then-else
tuyên bố.
Tuyên bố trường hợp
Hầu hết các ngôn ngữ lập trình đều có phiên bản switch
hoặc case
tuyên bố. Những điều này hướng luồng thực thi chương trình theo giá trị của một biến. Thông thường, có một nhánh thực thi được xác định cho mỗi giá trị có thể mong đợi của biến và một phần tóm tắt hoặc mặc định nhánh cho tất cả các giá trị khác.
Chức năng logic tương tự như một chuỗi dài của if-then
tuyên bố với một else
câu lệnh bắt mọi thứ mà trước đây chưa được xử lý bởi một trong các if
các câu lệnh.
Việc triển khai Bash của case
cố gắng khớp với một biểu hiện với một trong các mệnh đề. Nó thực hiện điều này bằng cách lần lượt xem xét từng mệnh đề, cố gắng tìm một kết quả phù hợp họa tiết. Các mẫu trong mệnh đề là các chuỗi, nhưng — ngược lại — điều đó không có nghĩa là chúng ta không thể sử dụng các giá trị số làm biểu thức.
Trường hợp chung
Dạng chung của case
tuyên bố là thế này:
case expression in pattern-1) statement ;; pattern-2) statement ;; . . . pattern-N) statement ;; *) statement ;; esac
- Một
case
câu lệnh phải bắt đầu bằngcase
từ khóa và kết thúc bằngesac
từ khóa. - Biểu thức được đánh giá và so sánh với các mẫu trong mỗi mệnh đề cho đến khi một kết quả phù hợp được tìm thấy.
- Câu lệnh hoặc các câu lệnh trong mệnh đề so khớp được thực thi.
- Dấu chấm phẩy kép “
;;
”Được sử dụng để kết thúc một mệnh đề. - Nếu một mẫu được khớp và các câu lệnh trong mệnh đề đó được thực thi, tất cả các mẫu khác sẽ bị bỏ qua.
- Không giới hạn số lượng mệnh đề.
- Dấu hoa thị “
*
”Biểu thị mẫu mặc định. Nếu một biểu thức không khớp với bất kỳ mẫu nào khác trongcase
câu lệnh mệnh đề mặc định được thực thi.
Một ví dụ đơn giản
Kịch bản này cho chúng ta biết giờ mở cửa của một cửa hàng tưởng tượng. Nó sử dụng date
lệnh với +"%a"
chuỗi định dạng để lấy tên ngày rút gọn. Điều này được lưu trữ trong DayName
Biến đổi.
#!/bin/bash DayName=$(date +"%a") echo "Opening hours for $DayName" case $DayName in Mon) echo "09:00 - 17:30" ;; Tue) echo "09:00 - 17:30" ;; Wed) echo "09:00 - 12:30" ;; Thu) echo "09:00 - 17:30" ;; Fri) echo "09:00 - 16:00" ;; Sat) echo "09:30 - 16:00" ;; Sun) echo "Closed all day" ;; *) ;; esac
Sao chép văn bản đó vào một trình chỉnh sửa và lưu nó dưới dạng tệp có tên “open.sh.”
Chúng tôi sẽ cần sử dụng chmod
lệnh để làm cho nó có thể thực thi được. Bạn sẽ cần làm điều đó cho tất cả các tập lệnh bạn tạo khi làm việc trong bài viết này.
chmod +x open.sh
Bây giờ chúng ta có thể chạy tập lệnh của mình.
./open.sh
Ngày chụp ảnh màn hình là một ngày thứ sáu. Điều đó có nghĩa là DayName
biến giữ chuỗi “Thứ sáu” Điều này phù hợp với mẫu “Thứ Sáu” của mệnh đề “Thứ Sáu)”.
Lưu ý rằng các mẫu trong mệnh đề không cần được đặt trong dấu ngoặc kép, nhưng nếu có thì cũng không gây hại gì. Tuy nhiên bạn cần phải sử dụng dấu ngoặc kép nếu mẫu chứa khoảng trắng.
Mệnh đề mặc định đã được để trống. Bất kỳ điều gì không phù hợp với một trong các mệnh đề trước sẽ bị bỏ qua.
Kịch bản đó hoạt động và rất dễ đọc, nhưng nó dài dòng và lặp đi lặp lại. Chúng ta có thể rút gọn loại case
tuyên bố khá dễ dàng.
Sử dụng nhiều mẫu trong một mệnh đề
Một tính năng thực sự gọn gàng của case
câu lệnh là bạn có thể sử dụng nhiều mẫu trong mỗi mệnh đề. Nếu biểu thức khớp với bất kỳ mẫu nào thì các câu lệnh trong mệnh đề đó sẽ được thực thi.
Đây là tập lệnh cho bạn biết có bao nhiêu ngày trong một tháng. Chỉ có thể có ba câu trả lời: 30 ngày, 31 ngày hoặc 28 hoặc 29 ngày cho tháng Hai. Vì vậy, mặc dù có 12 tháng nhưng chúng ta chỉ cần ba mệnh đề.
Trong tập lệnh này, người dùng được nhắc nhập tên của một tháng. Để làm cho mẫu đối sánh không phân biệt chữ hoa chữ thường, chúng tôi sử dụng shopt
lệnh với -s nocasematch
lựa chọn. Sẽ không thành vấn đề nếu đầu vào chứa chữ hoa, chữ thường hoặc hỗn hợp của cả hai.
#!/bin/bash shopt -s nocasematch echo "Enter name of a month" read month case $month in February) echo "28/29 days in $month" ;; April | June | September | November) echo "30 days in $month" ;; January | March | May | July | August | October | December) echo "31 days in $month" ;; *) echo "Unknown month: $month" ;; esac
Tháng Hai có một điều khoản cho chính nó, và tất cả các tháng khác chia sẻ hai điều khoản tùy theo việc họ có 30 hay 31 ngày trong đó. Các mệnh đề nhiều mẫu sử dụng ký hiệu ống “|” làm dấu phân cách. Trường hợp mặc định bắt các tháng bị đánh vần sai.
Chúng tôi đã lưu điều này vào một tệp có tên “month.sh” và làm cho nó có thể thực thi được.
chmod +x month.sh
Chúng tôi sẽ chạy tập lệnh nhiều lần và cho thấy rằng không quan trọng nếu chúng tôi sử dụng chữ hoa hay chữ thường.
./month.sh
Bởi vì chúng tôi đã yêu cầu tập lệnh bỏ qua sự khác biệt về chữ hoa và chữ thường, bất kỳ tên tháng nào được viết đúng chính tả sẽ được xử lý bởi một trong ba mệnh đề chính. Các tháng viết sai chính tả bị mắc phải bởi mệnh đề mặc định.
Sử dụng chữ số trong câu lệnh trường hợp
Chúng ta cũng có thể sử dụng các chữ số hoặc biến số làm biểu thức. Tập lệnh này yêu cầu người dùng nhập một số trong phạm vi 1..3. Để làm rõ rằng các mẫu trong mỗi mệnh đề là chuỗi, chúng được đặt trong dấu ngoặc kép. Mặc dù vậy, tập lệnh vẫn khớp với đầu vào của người dùng với mệnh đề thích hợp.
#!/bin/bash echo "Enter 1, 2, or 3: " read Number case $Number in "1") echo "Clause 1 matched" ;; "2") echo "Clause 2 matched" ;; "3") echo "Clause 3 matched" ;; *) echo "Default clause matched" ;; esac
Lưu tệp này vào một tệp có tên “number.sh”, làm cho tệp này có thể thực thi được rồi chạy:
./number.sh
Sử dụng các câu lệnh case trong for Loops
Một case
câu lệnh cố gắng khớp với một biểu thức duy nhất. Nếu bạn có nhiều biểu thức cần xử lý, bạn có thể đặt case
tuyên bố bên trong một for
vòng.
Tập lệnh này thực thi ls
lệnh để lấy danh sách các tệp. bên trong for
loop, file globbing — tương tự nhưng khác với biểu thức chính quy — lần lượt được áp dụng cho từng tệp để trích xuất phần mở rộng tệp. Điều này được lưu trữ trong Extension
biến chuỗi.
Các case
tuyên bố sử dụng Extension
biến dưới dạng biểu thức mà nó cố gắng so khớp với một mệnh đề.
#!/bin/bash for File in $(ls) do # extract the file extension Extension=${File##*.} case "$Extension" in sh) echo " Shell script: $File" ;; md) echo " Markdown file: $File" ;; png) echo "PNG image file: $File" ;; *) echo "Unknown: $File" ;; esac done
Lưu văn bản này vào một tệp có tên là “filetype.sh”, làm cho nó có thể thực thi được và sau đó chạy nó bằng cách sử dụng:
./filetype.sh
Tập lệnh xác định loại tệp tối giản của chúng tôi hoạt động.
Xử lý mã thoát với tuyên bố trường hợp
Một chương trình hoạt động tốt sẽ gửi một mã thoát đến trình bao khi nó kết thúc. Lược đồ thông thường sử dụng giá trị mã thoát bằng 0 để chỉ ra một thực thi không có sự cố và các giá trị của một hoặc nhiều để chỉ ra các loại lỗi khác nhau.
Nhiều chương trình chỉ sử dụng số không và một. Việc gộp tất cả các điều kiện lỗi vào một mã thoát duy nhất làm cho việc xác định các vấn đề khó khăn hơn, nhưng đó là một thực tế phổ biến.
Chúng tôi đã tạo một chương trình nhỏ có tên “go-geek” sẽ trả về ngẫu nhiên các mã thoát bằng 0 hoặc một. Tập lệnh tiếp theo này gọi go-geek
. Nó lấy mã thoát bằng cách sử dụng $?
biến shell và sử dụng biến đó làm biểu thức cho case
tuyên bố.
Một tập lệnh trong thế giới thực sẽ thực hiện xử lý thích hợp tùy theo sự thành công hay thất bại của lệnh tạo ra mã thoát.
#!/bin/bash go-geek case $? in "0") echo "Response was: Success" echo "Do appropriate processing in here" ;; "1") echo "Response was: Error" echo "Do appropriate error handling in here" ;; *) echo "Unrecognised response: $?" ;; esac
Lưu nó vào một tập lệnh có tên “return-code.sh” và làm cho nó có thể thực thi được. Bạn sẽ cần thay thế một số lệnh khác cho go-geek
yêu cầu. Bạn có thể thử cd
vào một thư mục không tồn tại để lấy mã thoát của một thư mục, sau đó chỉnh sửa tập lệnh của bạn thành cd
vào một thư mục có thể truy cập để nhận mã thoát bằng 0.
Chạy tập lệnh một vài lần cho thấy các mã thoát khác nhau được xác định chính xác bởi case
tuyên bố.
./return-code.sh
Tính dễ hiểu giúp khả năng duy trì
Quay trở lại các kịch bản Bash cũ và tìm ra cách chúng thực hiện những gì chúng làm, đặc biệt nếu chúng được viết bởi người khác, là một thách thức. Sửa đổi chức năng của các tập lệnh cũ thậm chí còn khó hơn.
Các case
câu lệnh cung cấp cho bạn logic phân nhánh với cú pháp rõ ràng và dễ hiểu. Đó là một đôi bên cùng có lợi.