Bash For Loop示例
警告!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密钥。