Bash For Loop示例

时间:2020-01-09 10:37:21  来源:igfitidea点击:

警告!seq命令打印一个数字序列,由于历史原因,它在这里。
以下示例仅推荐用于较旧的bash版本。
建议所有用户(bash v3.x +)使用以上语法。

for循环语法

语法的数值范围如下:

for VARIABLE in 1 2 3 4 5 .. N
do
	command1
	command2
	commandN
done

或者

for VARIABLE in file1 file2 file3
do
	command1 on $VARIABLE
	command2
	commandN
done

或者

for OUTPUT in $(Linux-Or-Unix-Command-Here)
do
	command1 on $OUTPUT
	command2 on $OUTPUT
	commandN
done

例子

这种for循环的特点是计数。
该范围由开始(#1)和结束数字(#5)指定。

for循环为项目列表中的每个成员执行一系列命令。

BASH中的一个代表性示例如下所示,使用for循环显示5次欢迎消息:

#!/bin/bash
for i in 1 2 3 4 5
do
   echo "Welcome $i times"
done

有时您可能需要设置一个步进值(例如,允许一个以2计数或向后计数)。
最新的bash版本3.0+具有内置的设置范围支持:

#!/bin/bash
for i in {1..5}
do
   echo "Welcome $i times"
done

Bash v4.0 +已内置支持使用{START..END..INCREMENT}语法设置步长值:

#!/bin/bash
echo "Bash version ${BASH_VERSION}..."
for i in {0..10..2}
  do 
     echo "Welcome $i times"
done

输出示例:

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

seq命令为Loop创建标准bash(过时的方法)

如何在Linux/UNIX操作系统下使用bash for loop重复执行某些任务?
如何使用for语句设置无限循环?
如何使用三参数进行循环控制表达式?

for循环是bash编程语言语句,它允许重复执行代码。

for循环被归类为迭代语句,即它是bash脚本中进程的重复。
例如,您可以运行UNIX命令或任务5次,或使用for循环读取和处理文件列表。
可以在shell提示符下或在shell脚本本身内使用for循环。

seq命令可以如下使用。

seq中的一个代表性示例如下:

#!/bin/bash
for i in $(seq 1 2 20)
do
   echo "Welcome $i times"
done

没有充分的理由使用诸如seq之类的外部命令来计数和递增for循环中的数字,因此建议您避免使用seq。
内置命令速度很快。

三表达式bash for循环语法

这种类型的for循环与C编程语言有着共同的传统。
它的特点是三参数循环控制表达式;由初始化程序(EXP1),循环测试或条件(EXP2)和计数表达式/步骤(EXP3)组成。

for (( EXP1; EXP2; EXP3 ))
do
	command1
	command2
	command3
done
## The C-style Bash for loop ##
for (( initializer; condition; step ))
do
  shell_COMMANDS
done

bash中具有代表性的三表达式示例如下:

#!/bin/bash
for (( c=1; c<=5; c++ ))
do  
   echo "Welcome $c times"
done

输出示例:

Welcome 1 times
Welcome 2 times
Welcome 3 times
Welcome 4 times
Welcome 5 times

如何用于无限循环?

可以使用空表达式创建无限for循环,例如:

#!/bin/bash
for (( ; ; ))
do
   echo "infinite loops [ hit CTRL+C to stop]"
done

有条件退出有休息

您可以使用for循环中的break语句来提前退出。
您可以使用break从FOR,WHILE或UNTIL循环中退出。

for循环内的常规break语句:

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

以下shell脚本将通过所有存储在/etc目录中的文件。
找到/etc/resolv.conf文件时,将放弃for循环。

#!/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

早期继续,继续执行语句

要恢复封闭的FOR,WHILE或UNTIL循环的下一个迭代,请使用Continue语句。

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

该脚本备份命令行上指定的所有文件名。
如果.bak文件存在,它将跳过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

带数组元素的循环

在此示例中,我们使用for循环遍历定义如下的元素数组:

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

用shell变量循环

有时,我们将重要数据存储在shell变量中,并且可以使用如下所示的循环读取数据:

_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

用数字循环

我们可以在循环中指定范围,如下所示:

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 al我有" 
    else
        echo "server $h dead or can not ping."
    fi
done

用字符串循环

假设我们有一个名为PKGS的变量,我们需要遍历字符串列表来安装这些软件包:

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

命令替换

命令替换意味着运行shell命令并将其输出存储到变量。
例如:

up=$(uptime)
echo "Server uptime is $up"

for循环参数列表还可以按以下方式执行命令替换:

for var in $(command)
do
  print "$var"
done
## example ##
for f in $(ls /nas/*.pdf)
do
  print "File $f"
done

命令行参数

命令行参数不过是发送给被调用程序的参数。
程序可以使用任意数量的命令行参数。
例如,我们将使用grep命令在/etc/passwd文件中搜索用户名:

$ grep 'Hyman' /etc/passwd

grep是实际命令的名称,当您在shell提示符下键入command时,shell将执行此命令。
命令行上的第一个单词是:

  • grep要执行的命令的名称。
  • 命令行上的其他所有内容均作为该命令的参数。

for循环参数列表还包含命令行参数/参数,如下所示:

## $@ expands to the positional parameters, starting from one.  ##
for i in $@
do
    echo "Script arg is $i"
done

您可以按以下方式运行它:

./script one foo bar

放在一起

Bash for loop对于自动化IT中的重复任务很有用。
让我们看看如何在多个Linux或Unix服务器上运行一个简单的命令(例如正常运行时间):

for s in server1 server2 server3
do
    ssh Hyman@${s} "uptime"
done

或将echo命令与命令替换结合在一起,如下所示:

for s in server1 server2 server3
do
    echo "Server ${s}: $(ssh Hyman@${s} uptime)"
done

输出示例:

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

在此标准bash for loop示例中,如果我们有基于Debian/Ubuntu的服务器,我们将使用yum命令或apt命令/apt-get命令来更新所有基于CentOS/RHEL的服务器:

## 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

这是简单但有用的shell脚本示例:

#!/usr/bin/env bash
# Purpose: Update all my Linode servers powered by Debian/Ubuntu Linux
# Author: Hyman 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=noninteract我有 apt-get -y -q upgrade >>"${log}"
done
echo "Check $log file for details."

了解为什么我们使用DEBIAN_FRONTEND apt-get变量来避免更新时出现任何提示。
最好是出于自动化目的或从Linux/Unix cron作业运行脚本而设置ssh密钥。