Cú pháp vòng lặp
Vòng lặp theo một khoảng số cú pháp như sau:
for VARIABLE in 1 2 3 4 5 .. N do command1 command2 commandN done
Hoặc
for VARIABLE in file1 file2 file3 do command1 on $VARIABLE command2 commandN done
Hoặc
for OUTPUT in $(Linux-Or-Unix-Command-Here) do command1 on $OUTPUT command2 on $OUTPUT commandN done
Ví dụ
Loại vòng lặp này được đặc trưng bằng cách đếm. Phạm vi được chỉ định bởi một số đầu (#1) và số kết thúc (#5). Vòng lặp for thực hiện một chuỗi các lệnh cho mỗi thành viên trong danh sách các mục. Một ví dụ đại diện trong BASH như sau để hiển thị thông báo chào 5 lần với vòng lặp
#!/bin/bash for i in 1 2 3 4 5 do echo "Welcome $i times" done
Đôi khi bạn có thể cần phải đặt một giá trị bước (cho phép một giá trị đếm bằng hai hoặc đếm ngược chẳng hạn). Bash phiên bản mới nhất 3.0+ có hỗ trợ tích hợp để thiết lập phạm vi:
#!/bin/bash for i in {1..5} do echo "Welcome $i times" done
Bash v4.0+ có hỗ trợ tích hợp để thiết lập giá trị bước bằng {START.. KẾT THÚC.. GIA TĂNG} cú pháp:
#!/bin/bash echo "Bash version ${BASH_VERSION}..." for i in {0..10..2} do echo "Welcome $i times" done
Đầu ra mẫu:
Bash version 4.0.33(0)-release... Welcome 0 times Welcome 2 times Welcome 4 times Welcome 6 times Welcome 8 times Welcome 10 times
Lệnh seq để tạo bash tiêu chuẩn cho Loop (phương pháp lỗi thời)
CẢNH BÁO! Lệnh seq in một chuỗi các số và nó ở đây vì lý do lịch sử. Các ví dụ sau đây chỉ được đề xuất cho phiên bản bash cũ hơn. Tất cả người dùng (bash v3.x+) nên sử dụng cú pháp trên.
Lệnh seq có thể được sử dụng như sau. Một ví dụ đại diện trong seq như sau:
#!/bin/bash for i in $(seq 1 2 20) do echo "Welcome $i times" done
Không có lý do chính đáng để sử dụng một lệnh bên ngoài như seq để đếm và tăng số trong vòng lặp for, do đó bạn nên tránh sử dụng seq. Lệnh builtin rất nhanh.
Ba biểu thức bash cho vòng lặp cú pháp
Loại vòng lặp này chia sẻ một di sản chung với ngôn ngữ lập trình C. Nó được đặc trưng bởi một biểu thức điều khiển vòng lặp ba tham số; bao gồm một initializer (EXP1), một loop-test hoặc condition (EXP2), và một biểu thức đếm/bước (EXP3).
for (( EXP1; EXP2; EXP3 )) do command1 command2 command3 done ## The C-style Bash for loop ## for (( initializer; condition; step )) do shell_COMMANDS done
Một ví dụ ba biểu thức đại diện trong bash như sau:
#!/bin/bash for (( c=1; c<=5; c++ )) do echo "Welcome $c times" done
Đầu ra mẫu:
Welcome 1 times Welcome 2 times Welcome 3 times Welcome 4 times Welcome 5 times
Làm thế nào để chúng ta sử dụng cho các vòng lặp vô hạn?
Vô hạn cho vòng lặp có thể được tạo bằng các biểu thức trống, chẳng hạn như:
#!/bin/bash for (( ; ; )) do echo "infinite loops [ hit CTRL+C to stop]" done
Output có điều kiện với ngắt
Bạn có thể thoát sớm với câu lệnh ngắt bên trong vòng lặp for. Bạn có thể thoát khỏi vòng lặp FOR, WHILE hoặc UNTIL bằng cách sử dụng ngắt. Câu lệnh ngắt chung bên trong vòng lặp for:
for I in 1 2 3 4 5 do statements1 #Executed for all values of ''I'', up to a disaster-condition if any. statements2 if (disaster-condition) then break #Abandon the loop. fi statements3 #While good and, no disaster-condition. done
Tập lệnh shell sau đây sẽ đi mặc dù tất cả các tệp được lưu trữ trong thư mục /etc. Vòng lặp cho sẽ bị từ bỏ khi tìm thấy tệp /etc/resolv.conf.
#!/bin/bash for file in /etc/* do if [ "${file}" == "/etc/resolv.conf" ] then countNameservers=$(grep -c nameserver /etc/resolv.conf) echo "Total ${countNameservers} nameservers defined in ${file}" break fi done
Tiếp tục sớm với tuyên bố tiếp tục
Để tiếp tục lặp lại lần lặp tiếp theo của vòng lặp FOR, WHILE hoặc UNTIL sử dụng câu lệnh tiếp tục.
for I in 1 2 3 4 5 do statements1 #Executed for all values of ''I'', up to a disaster-condition if any. statements2 if (condition) then continue #Go to next iteration of I in the loop and skip statements3 fi statements3 done
Tập lệnh này tạo bản sao lưu của tất cả các tên tệp được chỉ định trên dòng lệnh. Nếu .bak tồn tại, nó sẽ bỏ qua lệnh cp.
#!/bin/bash FILES="$@" for f in $FILES do # if .bak backup file exists, read next file if [ -f ${f}.bak ] then echo "Skiping $f file..." continue # read next file and skip the cp command fi # we are here means no backup file exists, just use cp command to copy file /bin/cp $f $f.bak done
Đối với vòng lặp với các phần tử mảng
Trong ví dụ này, chúng ta sử dụng vòng lặp for để lặp lại trên một mảng các phần tử được định nghĩa như sau:
DB_AWS_ZONE=('us-east-2a' 'us-west-1a' 'eu-central-1a') for zone in "${DB_AWS_ZONE[@]}" do echo "Creating rds (DB) server in $zone, please wait ..." aws rds create-db-instance \ --availability-zone "$zone" --allocated-storage 20 --db-instance-class db.m1.small \ --db-instance-identifier test-instance \ --engine mariadb \ --master-username my_user_name \ --master-user-password my_password_here done
Vòng lặp với biến shell
Đôi khi chúng ta lưu trữ dữ liệu quan trọng trong biến shell và chúng ta có thể sử dụng cho một vòng lặp như sau để đọc dữ liệu:
_admin_ip="202.54.1.33|MUM_VPN_GATEWAY 23.1.2.3|DEL_VPN_GATEWAY 13.1.2.3|SG_VPN_GATEWAY" for e in $_admin_ip do ufw allow from "${e%%|*}" to any port 22 proto tcp comment 'Open SSH port for ${e##*|}' done
Vòng lặp với một số
Chúng ta có thể chỉ định một phạm vi trong các vòng lặp như sau:
for i in {START..END} do commands done ## step value ## for i in {START..END..STEP} do commands done ## example: ping cbz01, cbz02, cbz03, and cbz04 using a loop ## for i in 0{1..4} do h="cbz${i}" ping -c 1 -q "$h" &>/dev/null if [ $? -eq 0 ] then echo "server $h alive" else echo "server $h dead or can not ping." fi done
Vòng lặp với các chuỗi
Giả sử chúng ta có một biến có tên PKGS và chúng ta cần lặp qua một danh sách các chuỗi để cài đặt các gói đó:
PKGS="php7-openssl-7.3.19-r0 php7-common-7.3.19-r0 php7-fpm-7.3.19-r0 php7-opcache-7.3.19-r0 php7-7.3.19-r0" for p in $PKGS do echo "Installing $p package" sudo apk add "$p" done
Thay thế lệnh
Thay thế lệnh có nghĩa là chạy lệnh shell và lưu trữ đầu ra của nó vào một biến. chẳng hạn:
up=$(uptime) echo "Server uptime is $up"
Danh sách đối số vòng lặp cũng hoạt động thay thế lệnh như sau:
for var in $(command) do print "$var" done ## example ## for f in $(ls /nas/*.pdf) do print "File $f" done
Đối số dòng lệnh
Một đối số dòng lệnh không là gì ngoài một đối số được gửi đến một chương trình đang được gọi. Một chương trình có thể lấy bất kỳ số lượng đối số dòng lệnh nào. Ví dụ: chúng ta sẽ sử dụng lệnh grep để tìm kiếm tên người dùng trong tệp /etc/passwd:
grep là tên của một lệnh thực tế và shell đã thực thi lệnh này khi bạn nhập lệnh tại dấu nhắc shell. Từ đầu tiên trên dòng lệnh là: $ grep 'vivek' /etc/passwd
- grep – tên của lệnh sẽ được thực thi.
- Mọi thứ khác trên dòng lệnh được lấy làm đối số cho lệnh này.
Danh sách đối số for Loop cũng accpents Đối số dòng lệnh/paramenters như sau:
## $@ expands to the positional parameters, starting from one. ## for i in $@ do echo "Script arg is $i" done
Bạn chạy nó như sau:./script one foo bar
Kết hợp tất cả lại với nhau
Bash cho vòng lặp rất hữu ích để tự động hóa các tác vụ lặp đi lặp lại trong IT. Hãy để chúng ta xem cách chạy một lệnh đơn giản (chẳng hạn như thời gian hoạt động) trên nhiều máy chủ Linux hoặc Unix:
for s in server1 server2 server3 do ssh vivek@${s} "uptime" done
HOẶC kết hợp lệnh echo cùng với lệnh thay thế như sau:
for s in server1 server2 server3 do echo "Server ${s}: $(ssh vivek@${s} uptime)" done
Đầu ra mẫu:
Server server1: 09:34:46 up 12 days, 21:57, 0 users, load average: 0.08, 0.09, 0.09 Server server2: 09:34:50 up 17 days, 2:30, 0 users, load average: 0.03, 0.03, 0.00 Server server3: 09:34:53 up 17 days, 2:31, 0 users, load average: 0.04, 0.04, 0.00
Ví dụ, trong bash tiêu chuẩn này, chúng ta sẽ cập nhật tất cả các máy chủ dựa trên CentOS / RHEL bằng lệnh yum hoặc lệnh apt/apt-get trong trường hợp chúng ta có máy chủ dựa trên Debian / Ubuntu:
## CENTOS/RHEL example (for fedora replace yum with dnf) ## for s in server0{1..8} do echo "*** Patching and updating ${s} ***" ssh root@${s} -- "yum -y update" done
Dưới đây là ví dụ tập lệnh shell đơn giản nhưng hữu ích:
#!/usr/bin/env bash # Purpose: Update all my Linode servers powered by Debian/Ubuntu Linux # Author: Vivek Gite under GPL v2.x+ # ---------------------------------------- log="/tmp/apt-get.log" >"${log}" for s in ln.cbz0{1..5} do echo "Updating and patching $s, please wait..." | tee -a "${log}" ssh root@${s} -- apt-get -q -y update >/dev/null ssh root@${s} -- DEBIAN_FRONTEND=noninteractive apt-get -y -q upgrade >>"${log}" done echo "Check $log file for details."
Xem lý do tại sao chúng ta DEBIAN_FRONTEND biến apt-get để tránh bất kỳ lời nhắc nào trong quá trình cập nhật. Sẽ là tốt nhất nếu bạn thiết lập các phím ssh cho mục đích tự động hóa hoặc chạy tập lệnh từ các công việc cron Linux / Unix.
Tìm thời gian ping cho nhiều địa chỉ IP
Đây là mã mẫu của chúng ta:
#!/bin/bash ips="$(host -t a www.hocdevops.com | awk '{ print $4}')" for i in $ips; do ping -q -c 4 "$i"; done
Điều này sẽ tạo ra số liệu thống kê trung bình như sau, cho thấy nhiều cân bằng tải ICMP ECHO_REQUEST thời gian trung bình là 19-20 mili giây
PING 104.22.10.214 (104.22.10.214) 56(84) bytes of data. --- 104.22.10.214 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3006ms rtt min/avg/max/mdev = 20.612/21.255/22.054/0.624 ms PING 172.67.7.239 (172.67.7.239) 56(84) bytes of data. --- 172.67.7.239 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3005ms rtt min/avg/max/mdev = 19.199/20.279/21.433/0.862 ms PING 104.22.11.214 (104.22.11.214) 56(84) bytes of data. --- 104.22.11.214 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3005ms rtt min/avg/max/mdev = 20.232/20.710/21.500/0.479 ms
kết thúc
Bạn đã học cách sử dụng bash cho vòng lặp với nhiều ví dụ khác nhau. Đối với các vòng lặp có thể tiết kiệm thời gian và giúp bạn tự động hóa cho các tác vụ nhỏ. Tuy nhiên, đối với các tác vụ tự động hóa phức tạp, bạn nên sử dụng các công cụ như Ansible, Salt, Chef, pssh và các công cụ khác.