Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Lập Trình Bash

Thành Thạo Vòng Lặp Bash: For, While, Until Giải Thích Chi Tiết

Thành Thạo Vòng Lặp Bash: For, While, Until Giải Thích Chi TiếtCâ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

  1. Vòng lặp For
  2. Vòng lặp While
  3. 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, do và done là từ khóa
  • List là bất kỳ danh sách nào có các mục
  • varname là 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, done là từ khóa
  • Expression là 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.