Câu lệnh lặp dùng để bắt chương trình thực thi liên tục một câu lệnh. Câu lệnh được thực thi gọi là thân vòng lặp.
Vòng lặp thực thi cho đến khi giá trị của biểu thức điều khiển là 0. Biểu thức điều khiển có thể là bất kỳ kiểu dữ liệu scalar nào.
Ngôn ngữ shell cũng cung cấp một số câu lệnh lặp. Trong bài này, chúng ta sẽ xem lại các câu lệnh lặp bash cung cấp dùng một số ví dụ.
Bash hỗ trợ ba loại câu lệnh lặp sau
- 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 Bash đang diễn ra.
Vòng lặp có thể lồng nhau. Giống bất kỳ ngôn ngữ lập trình nào, bash cũng hỗ trợ câu lệnh break để thoát vòng lặp hiện tại, và continue để tiếp tục lần lặp tiếp theo của câu lệnh lặp.
Vòng Lặp For Bash – Phương Pháp Thứ Nhất
Vòng lặp for thường dùng khi số lần lặp biết trước khi vào vòng lặp bash. Bash hỗ trợ hai loại for loop. Dạng đầu tiên của bash for loop là:
for varname in list do commands ## Body of the loop done
Trong cú pháp trên:
for,in,dovàdonelà từ khóaListlà bất kỳ danh sách nào có các mụcvarnamelà bất kỳ tên biến Bash nào.
Trong dạng này, câu lệnh for thực thi lệnh bao trong thân, một lần cho mỗi mục trong danh sách. Mục hiện tại từ danh sách sẽ lưu trong biến "varname" mỗi lần qua vòng lặp. varname này có thể xử lý trong thân vòng lặp. Danh sách này có thể là biến chứa nhiều từ phân tách bằng khoảng trắng. Nếu list bị thiếu trong câu lệnh for, nó lấy tham số vị trí được truyền vào shell.
Ví Dụ For Loop Bash 1. Giải Nén Tất Cả File Zip
Ví dụ sau tìm danh sách file khớp với "*.zip*" trong thư mục root, và tạo thư mục mới cùng vị trí file zip tồn tại, và giải nén nội dung file zip.
# cat zip_unzip.sh
#! /bin/bash
# Tìm file có .zip
for file in \`find /root -name "*.zip*" -type f\`
do
# Bỏ phần mở rộng .zip
dirname=\`echo ${file} | awk -F'.' '{print $1}'\`
# Tạo thư mục
mkdir $dirname
# Copy file zip
cp ${file} ${dirname}
cd $dirname
# Giải nén file zip từ thư mục mới tạo
unzip ${dirname}/\$(echo ${file##/*/})
done
- Trong ví dụ này lệnh find trả về danh sách file, từ đó mỗi file được xử lý qua vòng lặp.
- Với mỗi mục, nó tạo thư mục tên file zip, copy file zip vào thư mục mới và giải nén file zip từ đó.
- Câu echo,
echo ${file##/*/}cho chỉ tên file 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ự vòng lặp Bash, Awk cũng cung cấp for loop và while loop như thảo luận trong bài Awk While and For Loop.
Vòng Lặp For Bash – Phương Pháp Thứ Hai
Dạng thứ hai của for loop tương tự for loop trong ngôn ngữ 'C' lập trình, 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 bash for command trên, trước lần lặp đầu, expr1 được đánh giá. Thường dùng để khởi tạo biến cho vòng lặp.
- Tất cả câu lệnh giữa do và done thực thi lặp lại cho đến khi giá trị expr2 là TRUE.
- Sau mỗi lần lặp của vòng lặp, expr3 được đánh giá. Thường dùng để tăng bộ đếm vòng lặp.
Ví dụ sau tạo n số ngẫu nhiên.
Ví Dụ For Bash 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 số ngẫu nhiên tối đa max lần. RANDOM là hàm nội bộ bash trả về số nguyên ngẫu nhiên mỗi lần gọi.
Vòng Lặp While Bash
Câu lệnh lặp khác do ngôn ngữ shell cung cấp là câu lệnh while.
Syntax: while expression do commands done
Trong cú pháp while loop trên:
while,do,donelà từ khóaExpressionlà bất kỳ biểu thức nào trả về giá trị scalar- Câu lệnh while khiến khối mã được thực thi trong khi biểu thức điều kiện cho trước là đúng.
Ví Dụ While Bash 3. Ghi Nội Dung Vào File
Ví dụ sau đọc dữ liệu từ stdout và ghi vào file.
$ 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 file từ người dùng, và đọc các dòng dữ liệu từ stdin và thêm mỗi dòng vào tên file cho trước. Khi EOF nhập, read sẽ thất bại, nên vòng lặp kết thúc ở đó.
Nếu bạn viết nhiều script bash, bạn có thể dùng Vim editor như Bash IDE dùng plugin Vim bash-support như thảo luận trước.
Ví Dụ While Bash 4. Đọc Nội Dung File
Trong ví dụ trước, nó đọc dữ liệu từ stdout và ghi vào file. Trong ví dụ này, nó đọc nội dung file và ghi ra 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 file đọc, và dùng exec chuyển stdin đến file. Từ đó về sau, tất cả stdin đến từ file đó, thay vì bàn phím. Lệnh read đọc dòng từ stdin, nên while loop đọc stdin, cho đến khi EOF xảy ra.
Vòng Lặp Until Bash
Câu lệnh until rất giống về cú pháp và chức năng với câu lệnh while. Sự khác biệt thực sự duy nhất là câu lệnh until thực thi khối mã trong khi biểu thức điều kiện là sai, và câu lệnh while thực thi khối mã trong khi biểu thức điều kiệ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à từ khóa
expression bất kỳ biểu thức điều kiện
Ví Dụ Until Bash 5. Theo Dõi File Log
Ví dụ này theo dõi kích thước file log, một khi kích thước file log đạt 2000 bytes, nó copy bản sao file log đó.
$ 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 thi thân vòng lặp, cho đến khi điều kiện thành true. Trong ví dụ này điều kiện là kích thước file lớn hơn 2000 bytes, nên nó copy file khi đạt 2000 bytes.
Cũng tham khảo bài trước về ví dụ Mảng Bash.
Ví Dụ Until Bash 6. Chờ Máy Khởi Động
Ví dụ này dùng để chờ cho đến khi máy khởi động xong trước khi ssh đến máy đó. Câu lệnh until loop kết thúc chỉ khi ping trả về 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 tại dòng lệnh, như cách chờ đợi sự kiện cụ thể xảy ra.