Cách sử dụng câu lệnh Case trong tập lệnh Bash

Tác giả sysadmin, T.M.Hai 08, 2023, 09:16:42 SÁNG

« Chủ đề trước - Chủ đề tiếp »

0 Thành viên và 1 Khách đang xem chủ đề.

Cách sử dụng câu lệnh Case trong tập lệnh Bash


Bất chấp sức mạnh của nó, câu lệnh Case Bash giúp việc bảo trì tập lệnh Linux dễ dàng hơn.

  • Các câu lệnh bash case làm cho các tập lệnh dễ đọc và bảo trì hơn so với các câu lệnh if-then-else dài.
  • Câu lệnh Case trong Bash khớp một biểu thức với các mẫu trong mệnh đề và thực thi các câu lệnh tương ứng.
  • Có thể sử dụng nhiều mẫu trong một mệnh đề, giúp văn bản ngắn gọn và hiệu quả hơn. Các chữ số hoặc các biến số cũng có thể được sử dụng trong các câu lệnh Case.

Báo cáo Case Bash rất mạnh mẽ nhưng dễ viết. Khi xem lại tập lệnh Linux cũ, bạn sẽ rất vui vì đã sử dụng câu lệnh Case thay vì câu lệnh if-then-else dài dòng.

1. Case Statement

Hầu hết các ngôn ngữ lập trình đều có phiên bản câu lệnh switch hoặc case. Chúng điều khiển luồng thực hiện 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 từng giá trị dự kiến có thể có của biến và một nhánh bắt tất cả hoặc mặc đị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ác câu lệnh if-then với một câu lệnh khác nắm bắt mọi thứ chưa được một trong các câu lệnh xử lý trước đó.if

Việc triển khai Case Bash cố gắng khớp một biểu thức 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 ra mẫu phù hợp. Các mẫu trong mệnh đề là các chuỗi, nhưng—ngược lại trực giác—đ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.

2. Sử dụng Case chung

Hình thức chung của tuyên bố Case là thế này:

Mã nguồn [Chọn]
case expression in

  pattern-1)
    statement
    ;;

  pattern-2)
    statement
    ;;
   .
   .
   .

  pattern-N)
    statement
    ;;

  *)
    statement
    ;;
esac

  • Một câu lệnh case phải bắt đầu bằng từ khóa case và kết thúc bằng esactừ 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 tìm thấy kết quả khớp.
  • Câu lệnh hoặc các câu lệnh trong mệnh đề phù hợp sẽ được thực thi.
  • Dấu chấm phẩy kép " ;;" được dùng để chấm dứt 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 thì tất cả các mẫu khác sẽ bị bỏ qua.
  • Không có giới hạn về 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 trong câu lệnh Case thì mệnh đề mặc định sẽ được thực thi.

3. 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 datelệnh có +"%a"chuỗi định dạng để lấy tên ngày rút ngắn. Điều này được lưu trữ trong DayName biến.

Mã nguồn [Chọn]
#!/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 trình soạn thảo và lưu dưới dạng tệp có tên "open.sh."

Chúng ta sẽ cần sử dụng lệnh chmod để làm cho nó có thể thực thi được. Bạn sẽ cần phải làm điều đó cho tất cả các tập lệnh bạn tạo khi thực hiện bài viết này.

Mã nguồn [Chọn]
chmod +x open.sh
Bây giờ chúng ta có thể chạy tập lệnh của mình.

Mã nguồn [Chọn]
./open.sh

Ngày chụp ảnh màn hình xảy ra là thứ Sáu. Điều đó có nghĩa là biến DayName chứa chuỗi "Thứ Sáu". Điều này phù hợp với mẫu "Fri" của mệnh đề "Fri)".

Lưu ý rằng các mẫu trong các mệnh đề không cần phải đượ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 phải sử dụng dấu ngoặc kép nếu mẫu chứa dấu cách.

Mệnh đề mặc định đã được để trống. Bất kỳ điều gì không khớp với một trong các mệnh đề trước đều bị bỏ qua.

Kịch bản đó hoạt động tốt và dễ đọc nhưng dài dòng và lặp đi lặp lại. Chúng ta có thể rút ngắn kiểu tuyên bố Case đó khá dễ dàng.

4. Sử dụng nhiều mẫu trong một mệnh đề

Một tính năng thực sự thú vị của câu lệnh Case 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 trong số đó thì các câu lệnh trong mệnh đề đó sẽ được thực thi.

Đây là đoạn mã cho bạn biết một tháng có bao nhiêu ngày. 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, dù có 12 tháng nhưng chúng tôi chỉ cần 3 điều khoản.

Trong tập lệnh này, người dùng sẽ được nhắc nhập tên của một tháng. Để làm cho việc khớp mẫu không phân biệt chữ hoa chữ thường, chúng tôi sử dụng lệnh shopt với tùy chọn "-s nocasematch". Sẽ không thành vấn đề nếu dữ liệu đầu vào chứa chữ hoa, chữ thường hoặc kết hợp cả hai.

Mã nguồn [Chọn]
#!/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 mệnh đề riêng và tất cả các tháng khác đều có chung hai mệnh đề tùy theo chúng có 30 hay 31 ngày. Mệnh đề nhiều mẫu sử dụng ký hiệu ống "|" như là dấu phân cách. Trường hợp mặc định bắt tháng có lỗi đánh vần.

Chúng tôi đã lưu tệp này vào một tệp có tên "month.sh" và làm cho nó có thể thực thi được.

Mã nguồn [Chọn]
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 việc chúng tôi sử dụng chữ hoa hay chữ thường đều không thành vấn đề.

Mã nguồn [Chọn]
./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 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ả sẽ bị mắc vào mệnh đề mặc định.

5. Sử dụng chữ số trong câu lệnh Case

Chúng ta cũng có thể sử dụng các chữ số hoặc cá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à các chuỗi, chúng được gói trong dấu ngoặc kép. Mặc dù vậy, tập lệnh vẫn khớp dữ liệu đầu vào của người dùng với mệnh đề thích hợp.

Mã nguồn [Chọn]
#!/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

Mã nguồn [Chọn]
./number.sh

6. Sử dụng câu lệnh case trong vòng lặp for

Câu lệnh Case cố gắng khớp mẫu với một biểu thức. Nếu bạn có nhiều biểu thức cần xử lý, bạn có thể đặt câu lệnh case bên trong vòng lặp for.

Tập lệnh này thực thi lệnh ls để lấy danh sách các tệp. Trong vòng lặp for, toàn cầu hóa tệp—tương tự nhưng khác với các biểu thức thông thường —được áp dụng lần lượt 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 biến chuỗi Tiện ích mở rộng.

Câu lệnh Case sử dụng biến Tiện ích mở rộng làm biểu thức mà nó cố gắng khớp với một mệnh đề.

Mã nguồn [Chọn]
#!/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 "filetype.sh", làm cho nó có thể thực thi được và sau đó chạy nó bằng cách sử dụng:

Mã nguồn [Chọn]
./filetype.sh

Tập lệnh nhận dạng loại tệp tối giản của chúng tôi hoạt động.

6. Xử lý mã thoát với câu lệnh Case

Một chương trình hoạt động tốt sẽ gửi mã thoát tới shell khi nó kết thúc. Lược đồ thông thường sử dụng giá trị mã thoát bằng 0 để biểu thị việc thực thi không có vấn đề và các giá trị của một hoặc nhiều để biểu thị các loại lỗi khác nhau.

Nhiều chương trình chỉ sử dụng số 0 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 khiến việc xác định vấn đề trở nên khó khăn hơn, nhưng đó là thông lệ.

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 mã thoát bằng 0 hoặc một. Kịch bản 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 câu lệnh Case.

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 mã thoát.

Mã nguồn [Chọn]
#!/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 mã này vào 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 lệnh go-geek của chúng tôi. 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 thành thư mục có thể truy cập để lấy mã thoát bằng 0.

Chạy tập lệnh một vài lần sẽ hiển thị các mã thoát khác nhau được xác định chính xác bằng câu lệnh Case.

Mã nguồn [Chọn]
./return-code.sh

7. Tính dễ đọc giúp dễ bảo trì

Quay lại các tập lệnh 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. Việ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âu lệnh Case cung cấp cho bạn logic phân nhánh với cú pháp rõ ràng và dễ dàng. Đó là đôi bên cùng có lợi.