158. 【Linux】shell-脚本进阶(三)

文章详细介绍了BashShell中的for命令,包括基本用法、读取复杂值、从变量读取列表、更改字段分隔符以及使用通配符读取目录。同时,讨论了while和until命令的使用,以及如何进行嵌套循环。此外,提到了break和continue命令用于循环控制,以及如何处理循环输出,如重定向。文章旨在帮助读者更好地理解和运用Shell脚本中的循环结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、for 命令

bash shell 提供了 for 命令,允许你创建一个遍历一系列值的循环。每次迭代都使用其中一个值来执行已定义好的一组命令,

for var in list
do

    command

done

在 list 参数中,你需要提供迭代中需要用到的一系列值,

  • 在每次迭代中,变量 var 会包含列表中的当前值。第一次迭代会使用列表中的第一个值,第二次迭代使用第二个值,以此类推,知道列表中的所有值都过一遍,
  • 在 do 和 done 语句之间输入的命令可以是一条或多条标准的 bash shell 命令。在这些命令中,$var 变量包含着这次迭代对应的当前列表项中的值。

1.1 读取列表中的值

for 命令最基本的用法就是遍历 for 命令自身所定义的一系列值

# !/bin/bash
#  Program:
#        basic for command
#  History:
#  2021/12/18    junfenghe.cloud@qq.com  version:0.0.1

path=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export path


for test in Alabama Arizona Arkansas California Colorado
do

    echo "The next state is ${test}"

done


exit 0

1.2 读取列表中的复杂值

shell 看到了列表值中的单引号并尝试使用它们来定义一个单独的数据值,这真是把事情搞得一团糟。有两种方法可解决这个问题:

  • 使用转义字符(反斜线)来将单引号转移;
  • 使用双引号来定义用到单引号的值。
# !/bin/bash
#  Program:
#        another example of how to use the for command
#  History:
#  2021/12/18    junfenghe.cloud@q.com   version:0.0.1

path=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export path


for test in I don\'t know if "this'll" work
do

    echo "word: ${test}"


done



exit 0

1.3 从变量读取列表

通常 shell 脚本遇到的情况是,你将一系列值都集中存储在了一个变量中,然后需要遍历变量中的整个列表。

# !/bin/bash
#  Program:
#        using a variable to hold the list
#  History:
#  2021/12/18    junfenghe.cloud@qq.com  version:0.0.1

path=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export path


list="ALdjk djlsgkd dgskjn dsjgdkj dhn dsdsdn"
list=${list}" dingdsl"

for item in ${list}
do

    echo "Have you ever visited ${item}"

done


exit 0

1.4 更改字段分隔符

内部字段分隔符(internal field separator),IFS 环境变量定义了 bash shell 用作字段分隔符的一系列字符。默认情况下,bash shell 会将下列字段当做字段分隔符,

  • 空格
  • 制表符
  • 换行符

下面代码中所引文件的内容

# !/bin/bash
#  Program:
#        reading values from a file

path=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export path



file="states"
IFS_OLD=${IFS}
IFS=$'\n'
for state in $(cat ${file})
do

    echo "Visit beautiful ${state}"

done
IFS=${IFS_OLD}



exit 0

1.5 用通配符读取目录

可以用 for 命令来自动遍历目录中的文件。进行此操作时,必须在文件名或路径名中使用通配符。它会强制 shell 使用使用文件扩展匹配。文件扩展匹配是生成匹配指定通配符的文件名或路径名的过程。

在 Linux 中,目录名和文件名中包含空格当然是合法的。要适应这种情况,应该将变量用双引号圈起来。如果不这么做,遇到含有空格的目录名或文件名时就会有错误产生。

# !/bin/bash
#  Program:
#        iterating through multiple directires
#  History:
#  2021/12/18    junfenghe.cloud@qq.com  version:0.0.1

path=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export path


for file in /home/qij/.b*
do

    if [ -d "${file}" ]
    then

        echo "${file} is a directory"

    elif [ -f "${file}" ]
    then

        echo "${file} is a file"

    else

        echo "${file} does exist"

    fi

done


exit 0

2、while 命令

1.1 while 的基本格式

while 的基本格式,

while test command
do

    other commands

done
# !/bin/bash
#  Program:
#        while command test
#  History:
#  2021/12/18    junfenghe.cloud@qq.com  version:0.0.1

path=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export path


val1=10

while [ ${val1} -gt 0 ]
do

    echo ${val1}
    (( val1=${val1} - 1 ))

done


exit 0

3、until 命令

until 命令和 while 命令工作的方式完全相反。until 命令要求你指定一个通常返回非零退出状态码的测试命令。只有测试命令的退出状态码不为 0,bash shell 才会执行循环中列出的命令,一旦测试命令返回了退出状态 0,循环就结束了。

# !/bin/bash
#  Program:
#        using the until command
#  History:
#  2021/12/18    junfenghe.cloud@qq.com  version:0.0.1

path=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export path


val1=100

until [ ${val1} -eq 0 ]
do

    echo "${val1}"
    val1=$(( ${val1} - 25 ))

done


exit 0

4、嵌套循环

循环语句可以在循环内使用任意类型的命令,包括其他循环命令。这种循环叫做嵌套循环(nested loop)。注意,在使用嵌套循环时,你是在迭代中使用迭代,与命令运行的次数是乘积关系。不注意这点的话,有可能会在脚本中造成问题。

# /bin/bash
#  Program:
#        nesting for loops
#  History:
#  2021/12/18    junfenghe.cloud@qq.com  version:0.0.1

path=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export path


for (( a = 1; a <= 3; a++ ))
do

    echo "Starting loop ${a}"
    for (( b = 1;b <=3; b++ ))
    do

        echo "    Inside loop: ${b}"

    done

done


exit 0

# !/bin/bash
#  Program:
#        placing a for loop inside a while loop
#  History:
#  2021/12/18    junfenghe.cloud@qq.com  version:0.0.1

path=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export path


var1=5

while [ ${var1} -ge 0 ]
do

    echo "Outer loop: ${var1}"
    for (( var2 = 1; var2 < 3; var2++ ))
    do

        var3=$(( ${var1} * ${var2} ))
        echo "    Inside loop: ${var1} * ${var2} = ${var3}"

    done
    var1=$(( ${var1} - 1 ))

done


exit 0

# !/bin/bash
#  Program:
#        using until and while loops

path=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export path


var1=3

until [ ${var1} -eq 0 ]
do

    echo "Outer loop: ${var1}"
    var2=1
    while [ ${var2} -lt 5 ]
    do

        var3=$(echo "scale=4; ${var1} / ${var2}" | bc)
        echo "    Inner loop: ${var1} / ${var2} = ${var3}"
        var2=$(( ${var2} + 1 ))

    done
    var1=$(( ${var1} - 1 ))

done


exit 0

5、循环处理文件数据

通常必须遍历存储在文件中的数据。这要求结合已经讲过的两种技术:

  • 使用嵌套循环
  • 修改 IFS 环境变量
    通过修改 IFS 环境变量,就能强制 for 命令将文件中的每行都当成一个条目来处理,即便数据中有空格也是如此。一旦从文件中提取出了单独的行,可能需要再次利用循环来提取行中的数据。
# !/bin/bash
#  Program:
#        changing the IFS value
#  History:
#  2021/12/18    junfenghe.cloud@qq.com  version:0.0.1

path=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export path


IFS.OLD=${IFS}
IFS=$'\n'
for entry in $( cat "/etc/passwd" )
do

    echo "Values in ${entry} -"
    IFS=:
    for value in ${entry}
    do

        echo "    ${value}"

    done

done


exit 0

6、循环控制

6.1 break 命令

break 命令是退出循环的一个简单方法。可以用 break 命令来退出任意类型的循环,包括 while 和 until 循环。

# !/bin/bash
#  Program:
#        breaking out of an outer loop
#  History:
#  2021/12/18    junfenghe.cloud@qq.com  version:0.0.1

path=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export path


for (( a = 1; a < 4; a++ ))
do

    echo "Outer loop: ${a}"

    for (( b = 1; b < 100; b++ ))
    do

        if [ ${b} -gt 4 ]
        then

            break 2

        fi

        echo "    Inner loop: ${b}"

    done

done


exit 0


PS: 上述代码里的 break n,其中 n 指定了要跳出的循环层数。默认情况下,为 1,表名跳出的是当前的循环。如果你将 n 设为 2,break 命令就会停止下一级的外部循环。

6.2 continue 命令

continue 命令可以提前中止某次循环中的命令,但并不会完全中止整个循环。可以在循环内部设置 shell 不执行命令的条件。

# !/bin/bash
#  Program:
#        using the continue command
#  History:
#  2021/12/18    junfenghe.cloud@qq.com  version:0.0.1

path=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export path


for (( var1 = 1; var1 < 15; var1++ ))
do

    if [ ${var1} -gt 5 ] && [ ${var1} -lt 10 ]
    then

        continue

    fi

    echo "Iteration number: ${var1}"

done


exit 0

7、处理循环的输出

在 shell 脚本中,你可以对循环的输出使用管道或进行重定向。这可以通过在 done 命令之后添加一个处理命令来实现,

# !/bin/bash
#  Program:
#        redirecting the for output to a file
#  History:
#  2021/12/18    junfenghe.cloud@qq.com  version:0.0.1

path=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export path


for (( a = 1; a < 10; a++ ))
do

    echo "The number is ${a}"

done > test123.txt

echo "The command is finished."


exit 0


以上算是我今天整整一天的简单练习、简书输出、工作输出的一部分。其实学到这里的时候,我工作中要编写的一键部署自动化脚本已经优化的差不多了,还剩一点,后面接着去解决。
(其实此间最有成就感的还是工作中要写的那个一键部署自动化脚本,百把来行 shell 脚本,感觉就是洋洋洒洒的非常帅气,就是不便发出来,只能内部用。)

### Linux Shell 脚本编程进阶 Shell 脚本是一种强大的工具,用于自动化任务并提高工作效率。以下是几个高级主题及其应用实例: #### 处理命令行参数 可以利用 `$*` 和 `$@` 来处理未知数量的命令行参数[^1]。下面是一个简单的例子展示如何遍历这些参数: ```bash #!/bin/bash for token in "$@" do echo "Parameter: $token" done ``` 此脚本会逐一打印传入的所有参数。 #### 嵌套循环结构 嵌套 `for` 循环可用于复杂的数据操作场景。例如,在矩阵中填充特定字符[^2]: ```bash sum=5 for n in $(seq $sum); do for m in $(seq $sum); do if [ $m -lt $sum ]; then echo -n "■ " else echo "■" fi done done ``` 上述代码创建了一个由方块组成的正方形图案。 #### 用户交互与文件解析 通过读取 `/etc/passwd` 文件并向其中每位用户发送问候消息,可实现更复杂的逻辑控制: ```bash while IFS=: read -r username _ uid gid _; do echo "Hello, user '$username'. Your UID is $uid and GID is $gid." done < /etc/passwd ``` 这段程序展示了如何逐行分析配置文件的内容,并提取所需字段进行进一步处理。 #### 使用 Awk 进行数据过滤 Awk 是一种非常适合文本处理的语言。可以通过它获取命令行参数的数量以及具体值[^3]。另外还可以筛选满足条件记录,比如找出那些用户 ID 小于组 ID 的账号列表[^4]: ```bash awk 'BEGIN{FS=":"} {if ($3<$4) print $1}' /etc/passwd ``` 以上命令列出了所有符合条件的用户名。 #### 综合练习建议 为了更好地掌握 Shell 编程技巧,可以从以下几个方面入手设计自己的项目或者完成指定的任务: - **环境变量管理**:学习设置、修改和删除环境变量的方法。 - **错误检测机制**:加入适当的异常捕获功能到现有脚本里去增强其健壮性。 - **定时作业调度**:研究 cron 表达式的语法并通过实际案例熟悉它的用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值