循环

for

语法1:

  • 不只适合数字,还支持通配符通配文件名等
for NAME [in WORDS ... ] ; do COMMANDS; done
for 变量名(每一次列表的值都会赋给这个变量) in 列表(决定循环体执行的次数);do
 循环体(command)
done

语法2:

  • 只适合数字

  • 控制变量初始化:仅在运行到循环代码段时执行一次

  • 控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断

for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done

for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))
do
 循环体
done

范例

[root@centos ~]# for i in 1 2 3 a b c;do echo i=$i ;done
i=1
i=2
i=3
i=a
i=b
i=c
[root@centos ~]# for i in {1..3};do echo i=$i ;done
i=1
i=2
i=3
[root@centos ~]# for i in {1..3}{a..b};do echo i=$i ;done
i=1a
i=1b
i=2a
i=2b
i=3a
i=3b
[root@centos ~]# for i in {10..1};do echo i=$i ;done
i=10
i=9
i=8
i=7
i=6
i=5
i=4
i=3
i=2
i=1
[root@centos ~]# for i in {10..1..2};do echo i=$i ;done
i=10
i=8
i=6
i=4
i=2
[root@centos ~]# for i in {a..g..2};do echo i=$i ;done
i=a
i=c
i=e
i=g
[root@centos ~]# for i in `seq 10`;do echo i=$i ;done
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9
i=10
[root@centos ~]# for i in $(seq 10);do echo i=$i ;done
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9
i=10


#支持通配符*,便利整个目录(不支持递归子目录)
for i in *;do ls $i;done

for循环实现计算1到100相加之和

#语法1
sum=0;for i in {1..100};do ((sum+=i));done;echo $sum
sum=0;for i in {1..100};do let sum+=i;done;echo $sum
---------------------------------------------------------------------------------
#语法2
for ((sum=0,i=1;i<=100;i++));do ((sum+=i)) ;done; echo $sum
for ((sum=0,i=1;i<=100;i++));do let sum+=i ;done; echo $sum

for循环支持位置变量

[root@centos ~]# vim sum.sh
#!/bin/bash
## #********************************************************************
#Author:            xiangzheng
#QQ:                767483070
#Date:              2021-10-22
#FileName:         sum.sh
#URL:               https://www.xiangzheng.vip
#Email:             rootroot25@163.com
#Description:      The test script
#Copyright (C):     2021 All rights reserved
#********************************************************************
sum=0
for i in $@;do
    let sum+=i
done
echo sum=$sum


[root@centos ~]# ./sum.sh 2 4 6
sum=12

for循环实现九九乘法表

#语法1
#打印1x9:
for i in {1..9};do
    echo -n "${i}x9=$((i*9)) "
done
echo 

#打印九九乘法表:
for i in {1..9};do
    for j in `seq ${i}`;do
    echo -n "${j}x${i}=$((i*j)) "
    done
    echo
done

#打印九九乘法表(输出结果对齐):
for i in {1..9};do
    for j in `seq ${i}`;do
    echo -e "${j}x${i}=$((i*j))\t\c"
    done
    echo
done
---------------------------------------------------------------------------------------
#语法2
for ((i=1;i<=9;i++));do
    for ((j=1;j<=i;j++));do
    echo -e "${j}x${i}=$((i*j))\t\c"
    done
    echo
done

for无限循环

for((;;));do echo for;done

for循环嵌套范例

  • 注意先后顺序,不同的顺序执行结果则不同
#script
PROXY_HOST="10.0.0.8 10.0.0.18"
IP_LIST="10.0.0.28 10.0.0.38"

function host_down(){
    for IP in ${PROXY_HOST};do
        for IPLIST in ${IP_LIST};do
            for SOCK_NUM in `seq 4`;do #`seq 4`表示4个sock文件的不同命名
                echo ${IP} ${IPLIST} ${SOCK_NUM}
            done
        done
    done
}

host_down


#执行结果
10.0.0.8 10.0.0.28 1
10.0.0.8 10.0.0.28 2
10.0.0.8 10.0.0.28 3
10.0.0.8 10.0.0.28 4
10.0.0.8 10.0.0.38 1
10.0.0.8 10.0.0.38 2
10.0.0.8 10.0.0.38 3
10.0.0.8 10.0.0.38 4
10.0.0.18 10.0.0.28 1
10.0.0.18 10.0.0.28 2
10.0.0.18 10.0.0.28 3
10.0.0.18 10.0.0.28 4
10.0.0.18 10.0.0.38 1
10.0.0.18 10.0.0.38 2
10.0.0.18 10.0.0.38 3
10.0.0.18 10.0.0.38 4

while

语法

while CONDITION; do COMMANDS; done

while CONDITION; do
 循环体
done

语法说明

CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“true”,则执行一次循环;直到条件测试状态为“false”终止循环,因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正

进入条件:CONDITION为true

退出条件:CONDITION为false

while无限循环

while true; do
 循环体
done

while循环实现计算1到100相加之和

while read 特殊用法

while 循环的特殊用法,遍历文件或文本的每一行

生产中需要逐行处理的情况可以使用此语句

语法:

while read line; do
 循环体
done < /PATH/FROM/SOMEFILE

范例:

#交互式
[root@centos ~]# while read -p "姓名:" name;do echo $name;done
姓名:xiang
xiang
姓名:zheng
zheng

#非交互式
[root@centos ~]# vim name.txt
[root@centos ~]# cat name.txt 
xiang
zheng
[root@centos ~]# while read -p "姓名:" name;do echo $name;done < name.txt 
xiang
zheng

#非交互式2
[root@centos ~]# cat name.txt 
xiang
zheng
[root@centos ~]# cat name.txt | while read -p "姓名:" name;do echo $name;done
xiang
zheng

范例:访问量检测

until

和while循环正好相反,while循环是为真就会一直执行循环,而until是为假就会一直执行循环

语法

until COMMANDS; do COMMANDS; done

until CONDITION; do
 循环体
done

until无限循环

until false; do
 循环体
Done

范例

#如果为0,就执行sleep
until [ $result -eq 0 ] ;do
 sleep 1
done

循环控制语句:

continue

continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层

语法:

while CONDITION1; do
 CMD1
 ...
 if CONDITION2; then
 continue
 fi
 CMDn
 ...
done

范例:

break

break [N]:提前结束第N层整个循环,最内层为第1层

语法:

while CONDITION1; do
 CMD1
 ...
 if CONDITION2; then
 break
 fi
 CMDn
 ...
done

范例1:

sum=0
COLOR='echo -e \033[1;31m'
COLOR2='echo -e \033[1;32m'
END="\033[0m"
while true;do
 echo -e "\033[33;1m\c"
 cat <<EOF
1) 鲍鱼
2) 满汉全席
3) 龙虾
4) 燕窝
5) 帝王蟹
6) 退出
EOF
 echo -e "\033[0m"
 read -p "请点菜(1-6): " MENU
 case $MENU in
 1|4)
   $COLOR'菜价: $10'$END
   let sum+=10
   ;;
 3|5)
   $COLOR'菜价: $20'$END
   let sum+=20
   ;;
 2)
   $COLOR'菜价: $1000'$END
   let sum+=1000
   ;;
 6)
   $COLOR2"你点的菜总价格是 $sum"$END
   break
   ;;
 *)
   echo "点错了,没有这道菜"
   ;;
 esac
 $COLOR2"你点的菜总价格是 $sum"$END
done

范例2:

NUM=$[RANDOM%10]
while read -p "输入 0-9 之间的数字: " INPUT ;do
 if [ $INPUT -eq $NUM ];then
 echo "恭喜你猜对了!"
 break
 elif [ $INPUT -gt $NUM ];then
        echo "数字太大了,重新猜!"
 else
        echo "数字太小了,重新猜!"
    fi
done

shift

  • shift [n] 用于将参量列表 list 左移指定次数,缺省为左移一次。
  • 参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。
  • while 循环遍历位置参量列表时,常用到 shift

在Shell脚本中,shift是一个用于处理命令行参数的内建命令。它用于将位置参数(命令行参数)向左移动一个位置,并丢弃原来的第一个位置参数。这样,原来的第二个参数就成为新的第一个参数,依此类推。shift命令通常用于循环处理命令行参数,或者在函数中处理函数参数。

注意事项:

  • 需要注意的是,使用shift命令后,原来的第一个位置参数将不再可用。如果需要保留原始的位置参数,可以将其保存到其他变量中,以备后续使用。

shift 语法

shift [n]
  • n是一个可选的整数参数,指定要向左移动的位置参数的个数。
  • 如果不提供n,默认为1,即向左移动一个位置参数。

范例一

#!/bin/bash

## 循环处理命令行参数
while [ "$1" != "" ]; do
    echo "参数: $1"
    shift
done
  • 上述脚本将打印出传递给脚本的所有位置参数,并使用shift命令逐个处理它们。
  • 每次shift命令执行后,位置参数向左移动一个位置,直到没有剩余的位置参数为止。

以下是一个示例的输出,假设脚本名为script.sh,并且执行了以下命令:

$ ./script.sh arg1 arg2 arg3

输出将是:

参数: arg1
参数: arg2
参数: arg3
  • 在每次迭代中,shift命令将当前的第一个位置参数移除,而后续的位置参数则依次前移。
  • 因此,循环内的echo语句每次都打印出当前的第一个位置参数。

范例二

  • 利用$1和shift,创建多个账号。
## vim shift.sh
PASS=12345
while [ "$1" ];do
    useradd $1 && echo is created || echo $1 is exist
    echo $PASS | passwd --stdin $ &> /dev/null
    shift
done


## bash shift.sh haha xixi lala
is created
is created
is created


## getent passwd
...
haha:x:1004:1004::/home/haha:/bin/bash
xixi:x:1005:1005::/home/xixi:/bin/bash
lala:x:1006:1006::/home/lala:/bin/bash


## bash shift.sh haha xixi lala
useradd: user 'haha' already exists
haha is exist
useradd: user 'xixi' already exists
xixi is exist
useradd: user 'lala' already exists
lala is exist

范例三

  • 假设:./script.sh -u -h ftp.example.com -a username -p password -f file.txt
while [[ $# -gt 0 ]]; do
    key="$1"
    case $key in
        -u|--upload) # upload mode
        MODE="upload"; shift
        ;;
        -d|--download) # download mode
        MODE="download"; shift
        ;;
        -h|--host) # FTP server address
        FTP_HOST="$2"; shift 2
        ;;
        -a|--username) # non-anonymous login username
        FTP_USER="$2"; shift 2
        ;;
        -p|--password) # non-anonymous login password
        FTP_PASS="$2"; shift 2
        ;;
        -s|--subdir) # sub directory on FTP server
        SUB_DIR="$2/"; shift 2
        ;;
        -x|--proxy) # proxy server <host>:<port>
        PROXY="$2"; shift 2
        ;;
        -f|--file) # filename to upload or download
        FILE="$2"; shift 2
        ;;
        -*) # unknown options
        echo -e "Unknown option: $1\nTry '$0 --help' for more information." >&2; exit 1
        ;;
        *) # positional arguments
        echo -e "Unknown argument: $1\nTry '$0 --help' for more information." >&2; exit 1
        ;;
    esac
done

这段代码是一个处理命令行参数的脚本片段,它使用了while循环和case语句来逐个解析命令行参数,并将它们赋值给相应的变量。

让我们逐行解释这段代码的含义:

while [[ $# -gt 0 ]]; do

这行代码使用了while循环,条件是命令行参数的个数($#)大于0。这样可以确保在还有未处理的命令行参数时,循环会一直执行。

key="$1"

将当前的第一个命令行参数(即关键字)赋值给变量key

case $key in

开始case语句,根据变量key的值进行匹配。

-u|--upload) # upload mode
MODE="upload"; shift
;;

如果key的值匹配-u--upload,则表示是上传模式。将MODE变量设置为"upload",然后执行shift命令将命令行参数向左移动一个位置。

-d|--download) # download mode
MODE="download"; shift
;;

如果key的值匹配-d--download,则表示是下载模式。将MODE变量设置为"download",然后执行shift命令将命令行参数向左移动一个位置。

-h|--host) # FTP server address
FTP_HOST="$2"; shift 2
;;

如果key的值匹配-h--host,则表示是FTP服务器地址。将FTP_HOST变量设置为下一个位置参数的值(即FTP服务器地址),然后执行shift命令将命令行参数向左移动两个位置。

类似地,后续的-a|--username-p|--password-s|--subdir-x|--proxy-f|--file都是匹配不同的选项,并将相应的变量赋值。

-*) # unknown options
echo -e "Unknown option: $1\nTry '$0 --help' for more information." >&2; exit 1
;;

如果key-开头但不匹配已知选项,则表示是未知选项。脚本会打印错误消息,并以非零退出状态码退出。

*) # positional arguments
echo -e "Unknown argument: $1\nTry '$0 --help' for more information." >&2; exit 1
;;

如果key不匹配任何选项,则表示是位置参数。脚本会打印错误消息,并以非零退出状态码退出。

esac

结束case语句。

done

结束while循环。

通过这段代码,可以解析命令行参数并将其分配给相应的变量。例如,如果执行以下命令:

./script.sh -u -h ftp.example.com -a username -p password -f file.txt

根据给定的命令行参数,下面是代码的执行过程和变量的赋值:

  1. 循环开始,命令行参数个数为7(包括脚本名称)。
  2. 第一次迭代:
    • key被赋值为-u
    • case语句匹配到-u|--uploadMODE被设置为"upload"。
    • shift命令将命令行参数向左移动一个位置,此时命令行参数个数变为6。
  3. 第二次迭代:
    • key被赋值为-h
    • case语句匹配到-h|--hostFTP_HOST被设置为"ftp.example.com"。
    • shift命令将命令行参数向左移动两个位置,此时命令行参数个数变为4。
  4. 第三次迭代:
    • key被赋值为-a
    • case语句匹配到-a|--usernameFTP_USER被设置为"username"。
    • shift命令将命令行参数向左移动两个位置,此时命令行参数个数变为2。
  5. 第四次迭代:
    • key被赋值为-p
    • case语句匹配到-p|--passwordFTP_PASS被设置为"password"。
    • shift命令将命令行参数向左移动两个位置,此时命令行参数个数变为0。
  6. 循环结束,没有剩余的命令行参数。

在以上执行过程中,通过case语句的匹配,脚本将识别和处理各种选项和相应的参数。此外,如果出现未知选项或位置参数,脚本会打印错误消息并退出。

最后,根据处理命令行参数的结果,可以使用相应的变量(如MODEFTP_HOSTFTP_USERFTP_PASSFILE)进行后续操作,比如根据模式连接FTP服务器并上传或下载文件。

那么为什么其中有些是 shift 2 有的是 shift 呢?

在这段代码中,shift命令的参数表示要向左移动的位置参数的个数。有些选项需要移动两个位置参数,而有些只需要移动一个位置参数。

当一个选项需要处理一个附加的参数时,比如-h-a-p-s-x-f,它们的值紧跟在选项后面。因此,为了将这些选项及其参数正确地从命令行参数中移除,shift命令需要移动两个位置参数。

举个例子,当匹配到-h|--host选项时,需要获取FTP_HOST的值,并将该选项及其参数从命令行参数中移除。因此,shift 2会移动两个位置参数:选项本身的位置参数和其后的参数的位置参数。

而对于那些不需要处理附加参数的选项,比如-u-d,它们本身就是一个完整的选项。因此,在匹配到这些选项时,只需要将选项本身从命令行参数中移除,所以只需要执行shift命令移动一个位置参数。

通过根据选项需要处理的参数个数来决定使用shift还是shift 2,可以确保选项及其参数都被正确处理并从命令行参数中移除。

shell中的循环有哪些方式

在 shell 中,有多种不同的循环方式可供选择,下面是其中几种:

  1. for 循环:

for 循环通常用于遍历一系列值或文件名,可以使用以下语法:

bashCopy codefor var in list
do
    command1
    command2
    ...
done

其中,list 可以是一系列值或文件名,command1command2 等是在每次循环时执行的命令,var 是一个变量,用于存储当前循环中的值或文件名。

  1. while 循环:

while 循环可以在某个条件为真时执行一系列命令,可以使用以下语法:

while condition
do
    command1
    command2
    ...
done

其中,condition 是一个用于测试的条件表达式,command1command2 等是在每次循环时执行的命令。

  1. until 循环:

until 循环与 while 循环类似,但是只有当条件为假时才会执行一系列命令,可以使用以下语法:

bashCopy codeuntil condition
do
    command1
    command2
    ...
done

其中,condition 是一个用于测试的条件表达式,command1command2 等是在每次循环时执行的命令。

  1. select 循环:

select 循环通常用于从一系列值中选择一个,可以使用以下语法:

csharpCopy codeselect var in list
do
    command1
    command2
    ...
done

其中,list 是一系列值,var 是一个变量,用于存储用户选择的值,command1command2 等是在每次循环时执行的命令。

以上是 shell 中常用的几种循环方式,它们各有不同的用途和语法。

for 循环的语法有哪些,并展示几个范例

在 shell 中,for 循环有以下两种语法:

  1. 遍历一组值:
bashCopy codefor variable in value1 value2 ... valuen
do
    command1
    command2
    ...
done

其中,variable 是循环变量,value1 value2 ... valuen 是要遍历的一组值,command1command2 等是在每次循环时执行的命令。

例如,下面的示例循环遍历了一组数字:

bashCopy codefor i in 1 2 3 4 5
do
    echo $i
done

输出结果为:

Copy code1
2
3
4
5
  1. 遍历一个目录中的文件:
bashCopy codefor variable in directory/*
do
    command1
    command2
    ...
done

其中,variable 是循环变量,directory/* 是要遍历的目录中的所有文件,command1command2 等是在每次循环时执行的命令。

例如,下面的示例循环遍历了当前目录下的所有文件:

bashCopy codefor file in *
do
    echo $file
done

输出结果为当前目录下的所有文件名。

另一个示例是循环遍历指定目录下的所有文件,并打印出每个文件的类型:

bashCopy codefor file in /path/to/directory/*
do
    if [ -f "$file" ]; then
        echo "$file is a regular file"
    elif [ -d "$file" ]; then
        echo "$file is a directory"
    else
        echo "$file is not a regular file or directory"
    fi
done

以上是 for 循环的两种常见语法以及一些示例,可以根据具体的需求和场景选择不同的方式。

while 循环的语法有哪些,并展示几个范例

在 shell 中,while 循环有以下两种语法:

  1. 使用命令输出来控制循环:
bashCopy codewhile command
do
    command1
    command2
    ...
done

其中,command 是一个输出结果为 true 或 false 的命令,command1command2 等是在每次循环时执行的命令。

例如,下面的示例会循环读取用户输入的数字,直到输入的数字等于 0:

bashCopy codewhile true
do
    read -p "Enter a number (0 to exit): " num
    if [ $num -eq 0 ]; then
        break
    fi
    echo "You entered: $num"
done
  1. 使用条件表达式来控制循环:
bashCopy codewhile [ condition ]
do
    command1
    command2
    ...
done

其中,condition 是一个用于测试的条件表达式,command1command2 等是在每次循环时执行的命令。

例如,下面的示例循环打印数字 1 到 5:

bashCopy codenum=1
while [ $num -le 5 ]
do
    echo $num
    num=$((num+1))
done

输出结果为:

Copy code1
2
3
4
5

另一个示例是循环读取一个文件中的内容,并在每一行前加上行号:

bashCopy codefilename="file.txt"
line=1
while read -r content
do
    echo "$line: $content"
    line=$((line+1))
done < "$filename"

以上是 while 循环的两种常见语法以及一些示例,可以根据具体的需求和场景选择不同的方式。