Các câu lệnh lặp được sử dụng để buộc một chương trình thực hiện lặp lại một câu lệnh. Câu lệnh được thực thi được gọi là phần thân của vòng lặp.
Các vòng lặp thực thi cho đến khi giá trị của biểu thức điều khiển bằng 0. Biểu thức điều khiển có thể là bất kỳ kiểu dữ liệu vô hướng nào.
Ngôn ngữ shell cũng cung cấp một số câu lệnh lặp hoặc lặp. Trong bài viết này, chúng ta hãy xem xét các câu lệnh lặp mà bash cung cấp bằng cách sử dụng một số ví dụ.
Bash hỗ trợ ba loại câu lệnh lặp sau đây
- Vòng lặp for
- Vòng lặp While
- Vòng lặp Until
Bài viết này là một phần của loạt bài Hướng dẫn về Bash đang thực hiện.
Các vòng lặp có thể được lồng vào nhau. Giống như bất kỳ ngôn ngữ lập trình nào khác, bash cũng hỗ trợ câu lệnh break để thoát khỏi vòng lặp hiện tại và câu lệnh continue để tiếp tục lặp lại câu lệnh lặp tiếp theo.
Bash For Loop - Phương pháp đầu tiên
Vòng lặp for thường được sử dụng khi biết số lần lặp trước khi vào vòng lặp bash. Bash hỗ trợ hai loại vòng lặp for. Dạng đầu tiên của vòng lặp bash for là:
for varname in list do commands ##Body of the loop done
Trong cú pháp trên:
- cho, trong, làm và hoàn thành là các từ khóa
- Danh sách là bất kỳ danh sách nào có danh sách các mục
- varname là bất kỳ tên biến Bash nào.
Trong biểu mẫu này, câu lệnh for thực hiện lệnh nằm trong một phần nội dung, một lần cho mỗi mục trong danh sách. Mục hiện tại từ danh sách sẽ được lưu trữ trong một biến “varname” mỗi lần qua vòng lặp. Varname này có thể được xử lý trong phần thân của vòng lặp. Danh sách này có thể là một biến chứa một số từ được phân tách bằng dấu cách. Nếu thiếu danh sách trong câu lệnh for, thì nó sẽ nhận tham số vị trí đã được truyền vào shell.
Bash For Loop Ví dụ 1. Giải nén tất cả tệp Zip
Ví dụ sau đây tìm danh sách các tệp phù hợp với “* .zip *” trong thư mục gốc và tạo một thư mục mới ở cùng vị trí nơi tệp zip tồn tại và giải nén nội dung tệp zip.
# cat zip_unzip.sh #! /bin/bash # Find files which has .zip for file in `find /root -name "*.zip*" -type f` do # Skip the extension .zip dirname=`echo ${file} | awk -F'.' '{print $1}'` # Create the directory mkdir $dirname # Copy the zip file cp ${file} ${dirname} cd $dirname # Unzip the zip file from newly created directory unzip ${dirname}/$(echo ${file##/*/}) done
- Trong ví dụ này, lệnh find trả về danh sách các tệp, từ đó mỗi tệp sẽ được xử lý thông qua một vòng lặp.
- Đối với mỗi mục, nó sẽ tạo thư mục với tên của tệp zip và sao chép tệp zip vào thư mục mới được tạo và giải nén tệp zip từ đó.
- Câu lệnh echo, echo $ {file ## / * /} chỉ cung cấp cho bạn tên tệp chứ không phải đường dẫn.
# ./zip_unzip.sh Archive: /root/test2/test2.zip extracting: t1/p extracting: t1/q extracting: t1/r extracting: t1/s extracting: t1/t extracting: t1/u extracting: t1/v Archive: /root/test1/test1.zip extracting: t/a extracting: t/b extracting: t/c extracting: t/d extracting: t/e
Tương tự như vòng lặp Bash, Awk cũng cung cấp vòng lặp for và vòng lặp while như chúng ta đã thảo luận trong bài viết Awk While và For Loop.
Bash For Loop - Phương pháp thứ hai
Dạng thứ hai của vòng lặp for tương tự như vòng lặp for trong ngôn ngữ lập trình ‘C’, có ba biểu thức (khởi tạo, điều kiện và cập nhật).
for (( expr1; expr2; expr3 )) do commands done
- Trong cú pháp lệnh bash for ở trên, trước lần lặp đầu tiên, expr1 được đánh giá. Điều này thường được sử dụng để khởi tạo các biến cho vòng lặp.
- Tất cả các câu lệnh giữa do và done được thực thi lặp đi lặp lại cho đến khi giá trị của expr2 là TRUE.
- Sau mỗi lần lặp lại của vòng lặp, expr3 được đánh giá. Điều này thường được sử dụng để tăng bộ đếm vòng lặp.
Ví dụ sau tạo ra n số ngẫu nhiên.
Bash Ví dụ 2. Tạo n số ngẫu nhiên
$ cat random.sh #! /bin/bash echo -e "How many random numbers you want to generate" read max for (( start = 1; start <= $max; start++ )) do echo -e $RANDOM done $ ./random.sh How many random numbers you want to generate 5 6119 27200 1998 12097 9181
Trong đoạn mã trên, vòng lặp for tạo ra số ngẫu nhiên ở số lần tối đa. RANDOM là một hàm bash nội bộ trả về một số nguyên ngẫu nhiên tại mỗi lần gọi.
Bash While Loop
Một câu lệnh lặp khác được cung cấp bởi ngôn ngữ lập trình shell là câu lệnh while.
Syntax: while expression do commands done
Trong cú pháp vòng lặp while ở trên:
- while, do, done là các từ khóa
- Biểu thức là bất kỳ biểu thức nào trả về giá trị vô hướng
- Câu lệnh while khiến một khối mã được thực thi trong khi biểu thức điều kiện đã cung cấp là đúng.
Bash While Ví dụ 3. Ghi nội dung vào tệp
Ví dụ sau đây đọc dữ liệu từ stdout và ghi vào một tệp.
$ cat writefile.sh #! /bin/bash echo -e "Enter absolute path of the file name you want to create" read file while read line do echo $line >> $file done $ sh writefile.sh Enter absolute path of the file name you want to create /tmp/a while for until $ cat /tmp/a while for until
Ví dụ trên, đọc tên tệp từ người dùng và đọc các dòng dữ liệu từ stdin và nối mỗi dòng với một tên tệp nhất định. Khi EOF vào, quá trình đọc sẽ không thành công, vì vậy vòng lặp kết thúc ở đó.
Nếu bạn đang viết nhiều tập lệnh bash, bạn có thể sử dụng Vim editor làm IDE Bash bằng cách sử dụng plugin Vim bash-support như chúng ta đã thảo luận trước đó.
Bash While Ví dụ 4. Đọc nội dung của tệp
Trong ví dụ trước, nó đọc dữ liệu từ stdout và ghi nó vào một tệp. Trong ví dụ này, nó đọc nội dung tệp
và ghi nó vào một stdout.
$ cat read.sh #! /bin/bash echo -e "Enter absolute path of the file name you want to read" read file exec <$file # redirects stdin to a file while read line do echo $line done $ ./read.sh Enter absolute path of the file name you want to read /tmp/a while for until
Trong ví dụ này, nó lấy tên tệp để đọc và sử dụng tệp thực thi, nó chuyển hướng stdin đến một tệp. Kể từ thời điểm đó, tất cả stdin đến từ tệp đó, chứ không phải từ bàn phím. lệnh read đọc dòng từ stdin, vì vậy vòng lặp while đọc stdin, cho đến khi EOF xảy ra.
Bash Until Loop
Câu lệnh Until rất giống về cú pháp và chức năng của câu lệnh while. Sự khác biệt thực sự duy nhất giữa cả hai là câu lệnh Until thực thi khối mã của nó trong khi biểu thức điều kiện của nó là sai và câu lệnh while thực thi khối mã của nó trong khi biểu thức điều kiện của nó là đúng.
syntax: until expression do commands #body of the loop done
Trong cú pháp bash Until ở trên:
where Until, do, done là các từ khóa
biểu thức bất kỳ biểu thức điều kiện nào
Bash Until Ví dụ 5. Theo dõi tệp nhật ký
Ví dụ này giám sát kích thước của logfile, khi kích thước logfile đạt 2000byte, nó sẽ lấy bản sao của logfile đó.
$ cat monitor.sh file=/tmp/logfile until [ $(ls -l $file | awk '{print $5}') -gt 2000 ] do echo "Sleeping for next 5 seconds" sleep 5 done date=`date +%s` cp $file "$file-"$date.bak $ ./monitor.sh Sleeping for next 5 seconds Sleeping for next 5 seconds $ ls -l /tmp/logfile* -rw-r--r-- 1 sss sss 2010 Jun 24 12:29 logfile -rw-r--r-- 1 sss sss 2005 Jun 24 16:09 logfile-1277474574.bak
Câu lệnh Until tiếp tục thực hiện phần thân của vòng lặp, cho đến khi điều kiện trở thành true. Trong điều kiện ví dụ này là kích thước của tệp lớn hơn 2000 byte, vì vậy nó sẽ sao chép tệp khi nó đạt đến 2000 byte.
Ngoài ra, hãy nhớ tham khảo các ví dụ về Mảng Bash trước đây của chúng tôi.
Bash Until Ví dụ 6. Chờ Máy khởi động
Ví dụ này được sử dụng để đợi cho đến khi máy xuất hiện trước khi thực hiện một ssh cho máy đó. Câu lệnh lặp cho đến khi kết thúc chỉ khi ping đưa ra phản hồi.
$ cat mac_wait.sh #! /bin/bash read -p "Enter IP Address:" ipadd echo $ipadd until ping -c 1 $ipadd do sleep 60; done ssh $ipadd $./mac_wait.sh Enter IP Address:192.143.2.10 PING 192.143.2.10 (192.143.2.10) 56(84) bytes of data. --- 192.143.2.10 ping statistics --- 1 packets transmitted, 0 received, 100% packet loss, time 0ms PING 192.143.2.10 (192.143.2.10) 56(84) bytes of data. 64 bytes from 192.143.2.10: icmp_seq=1 ttl=64 time=0.059 ms --- 192.143.2.10 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.059/0.059/0.059/0.000 ms The authenticity of host '192.143.2.10 (192.143.2.10)' can't be established. Are you sure you want to continue connecting (yes/no)? yes
Vòng lặp Until khá hữu ích ở dòng lệnh, như một cách để đợi các sự kiện nhất định xảy ra.