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="[email protected]"
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:

## [email protected] 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 [email protected]${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.

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments