Bash For 循环

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

如何在定义的时间段内循环运行某个命令。
或者,我们如何仅在n次内在一个范围内迭代任务。
所有这些都可以在Linux和Unix中使用bash for loop实现

在"什么是循环"中,"循环是指一系列指令,不断重复直到达到特定条件为止"。

因此,我们知道循环是一种情况,在这种情况下,我们可以在特定的预定时间段内重复执行某些任务,或者有时是无限的。

在我们的日常任务中使用这样的循环对于使用脚本自动执行任务非常有用。
可以根据个人的需要使用for,while,toish等配置循环。
在本教程中,我们将详细了解bash for loop,以及它在Linux环境中用于不同类型的自动化shell脚本的用法。

我还将分享使用for循环的不同Shell脚本示例,以了解其用法。

Bash中的基本for循环语法

for循环的语法将根据我们选择的编程语言(例如C,perl,python,go等)而有所不同。
提供的"语法"只能与bash和shell脚本一起使用

for {ELEMENT} in ${ARRAY[@]}
do
    {COMMAND}
done

了解语法

  • 其中:" ARRAY"可以包含任何类型的元素,例如字符串,整数。

  • 尽管将ARRAY传递给循环很重要,就像传递VARIABLE一样,然后循环将来自VARIABLE的所有ELEMENTS视为一个ELEMENT
    我将在本文稍后向我们展示这意味着什么

  • 循环会从"数组"中迭代每个"元素",并且可以将某些命令分配给这些"元素"

  • 循环将一直运行到ARRAY的最后一个ELEMENT为止。

EX_1:循环显示一系列数字

在我们的第一个shell脚本中,我们将遍历一个数字范围并打印该数字

for num in 1 2 3 4 5 6
do
   echo "Found Element: $num"
done

其中:我们传递了一系列用空格隔开的数字

该脚本的输出

Found Element: 1
Found Element: 2
Found Element: 3
Found Element: 4
Found Element: 5
Found Element: 6

EX_2:遍历一系列字符串

在这个shell脚本中,我们将遍历一系列字符串

for string in STRING1 STRING2 STRING3
do
   echo "Found Element: $string"
done

该脚本的输出:

Found Element: STRING1
Found Element: STRING2
Found Element: STRING3

让我们还为Linux管理员举一个"实际示例"。

在此脚本中,我们将编写一个小脚本,该脚本将在/tmp下搜索file1file2file3
如果我们不使用for循环,则必须手动搜索这些文件。
"我们可能会想,那么手动查找文件会更容易些吗。
"

是的," TRUE",但是如果我们有100个文件或者1000个文件怎么办。
我们会手动找到它们吗。

for file in file1 file2 file3
do
   echo "Searching for file: $file"
   file_path=`find /tmp -name $file`
   if [ ! -z $file_path ];then
      echo "Found: $file at $file_path"
   else
      echo "Not Found: $file"
   fi
done

脚本的输出将告诉我们找到的文件和找不到的文件。

重击循环范围

EX_3:用于数组的循环

在我们继续之前,重要的是要了解ARRAY和Variable之间的区别

数组与变量

  • 重要的是,在使用循环时,请使用包含以白色字符分隔的元素的"数组"。

  • 变量将始终包含单个元素,而数组可以包含多个元素

  • 数组还可以存储多个变量

  • 我们可以使用不同的方法将VARIABLE转换为ARRAY。

例如:

VAR="My name is hynman"

其中:我们给定了空格分隔的值,所以这变成了" ARRAY"吗。
"不,这是一个变量"

检查此VARIABLE的长度

echo "Length: ${#VAR[@]}"
Length: 1

Bash只能在此处计算单个元素,因此,如果我们尝试使用此VAR进行迭代,则只会得到1迭代

我们应该知道`如何在shell脚本中声明一个数组':

现在,我将声明与数组相同的内容

VAR=(My name is hynman)

其中:我在括号内添加了元素,现在让我们检查此变量的长度

# echo "Length: ${#VAR[@]}"
Length: 4

因此,现在bash将其视为具有4个ELEMENTS的ARRAY。

1st - My
2nd - name
3rd - is
4th - hynman

我们可以使用${VAR [$num]}来访问这些单独的元素。

这里的$num应该替换为我们想要访问的元素编号,例如:

#!/bin/bash
VAR=(My name is hynman)
echo "First Element: ${VAR[0]}"
echo "First Element: ${VAR[1]}"
echo "First Element: ${VAR[2]}"
echo "First Element: ${VAR[3]}"

该脚本的输出:

重击循环数组

让我们以一个"实际示例"来理解实时环境中的数组循环。
假设我们必须创建5个用户,并为这些用户分配密码。
在此Shell脚本中,我将为所有用户分配Passw0rd作为密码

#!/bin/bash
USERS=(user1 user2 user3 user4 user5)
for user in ${USERS[@]}
do
    echo "Creating user $user"
    useradd $user
    echo "Assigning password for $user"
    echo "Passw0rd" | passwd "$user" --stdin
done

EX_4:以C程序员的身份在bash中使用for循环

  • Bash扩展了for关键字,以提供与在C中使用双括号的三参数`for循环类似的功能。

  • 当我们要迭代的范围较小时,可以使用上面的示例,但是如果我们有较大范围的项,该怎么办。

  • 或者,如果我们不知道循环必须运行的次数,而是从脚本内部获取此值。

语法:

for ((ASSIGN_VALUE; ASSIGN_LIMIT ; STEP_UP)) 
do
  [COMMANDS]
done
  • 在此示例脚本中,"语法"将更加清晰。

  • "第一个表达式"在循环开始之前运行:我们将" i"值分配为零以将其启动。

  • "第二个表达式"是用于确定循环是继续还是停止的测试:我们测试" i"的值是否小于5.

  • 第三个表达式会在循环的每个实例之后运行:我们将一个加到i的值上。

#!/bin/bash
for (( i=0; i<=5; i++ ))
do
    echo "Iteration "
done

该脚本的输出:

Iteration 0
Iteration 1
Iteration 2
Iteration 3
Iteration 4
Iteration 5

现在,我们一定想知道`在实时场景中,我们是否有这样的" for循环"用例。

答案是肯定的。
我将分享一些实时场景,以更好地理解:

  • 在此示例中,我将在/tmp下搜索语法与file *匹配的所有文件。

  • 然后将一些内容添加到这些文件

  • 现在,循环应根据找到的文件数进行迭代

  • 因为迭代从" 0"开始,所以我们给变量" i"比找到的文件数少一个

#!/bin/bash
file_path=(`find /tmp -name "file*" -type f`)
echo "Found ${#file_path[@]} files"
for (( i=1; i<${#file_path[@]}; i++ )) 
do 
     echo "Adding content to ${file_path[$i]}" 
     echo "add some content" >> "${file_path[$i]}"
done

该脚本的输出:

bash for循环示例

定义多个变量

我们也可以在单个for循环中使用"多个变量"。
在此示例中,我定义了两个变量,循环将循环执行,直到" i"小于等于" j"变量为止

#!/bin/bash
for (( i=1,j=5; i<=j; i++,j-- ))
do
    echo "Iteration for i=$i"
    echo "Iteration for j=$j"
done

该脚本的输出

Iteration for i=1
Iteration for j=5
Iteration for i=2
Iteration for j=4
Iteration for i=3
Iteration for j=3

在此脚本中,我将使用带有bash的单个for循环中的"两个变量"来执行更多操作

for (( i=0, j=0 ; i+j < 5 ; i++, j++ ))
do
    echo "Value for i=$i"
    echo "Value for j=$j"
    echo "Multiply: $((i*j))"
    echo "add: $((i+j))"
done

该脚本的输出

Value for i=0
Value for j=0
Multiply: 0
add: 0
Value for i=1
Value for j=1
Multiply: 1
add: 2
Value for i=2
Value for j=2
Multiply: 4
add: 4

EX_5:使用继续语句

现在,我们不必执行要完成完整迭代的任务,有可能我们可能有特定要求在迭代运行期间"忽略某些值"。

for (( i=0 ; i<=5 ; i++ ))
do
    if [ $i -eq 2 ];then
       echo "Don't do anything when i=2"
    fi
    echo "Doing something when i=$i"
done

现在,当变量i的值等于2时,我还要进行一次检查,因此当匹配时,脚本应该不执行任何操作并继续进行其余的迭代

但是让我们检查一下此脚本的输出

Doing something when i=0
Doing something when i=1
Don't do anything when i=2
Doing something when i=2
Doing something when i=3
Doing something when i=4
Doing something when i=5

即使我添加了忽略" i = 2"匹配的检查,我们仍然看到在i = 2时正在做某事,因此"如何解决此问题。
"在这种情况下,我们需要使用" continue"语句

continue语句将退出循环的当前迭代,并将继续循环中的下一个迭代。

for (( i=0 ; i<=5 ; i++ ))
do
    if [ $i -eq 2 ];then
       echo "Don't do anything when i=2"
       continue
    fi
    echo "Doing something when i=$i"
done

该脚本的输出

Doing something when i=0
Doing something when i=1
Don't do anything when i=2
Doing something when i=3
Doing something when i=4
Doing something when i=5

现在我们看到,当变量" i"等于" 2"时,迭代将被跳过,循环将继续进行剩余的迭代

EX_6:使用break语句

使用continue,我们可以跳过循环进行单次迭代,但是如果我们想在特定条件下完全退出循环该怎么办呢。
等于2,所以在if条件下,我添加了一个break语句

for (( i=0 ; i<=5 ; i++ ))
do
    if [ $i -eq 2 ];then
       echo "Exiting, match sucessful"
       break
    fi
    echo "Doing something when i=$i"
done

该脚本的输出

Doing something when i=0
Doing something when i=1
Exiting, match successful

不出所料,当使用break语句满足if条件时,我们的for循环终止。

EX_7:一个衬套用于循环示例

我们可以使用以下" syntax"命令在一个内衬命令中编写for循环以执行简单的任务:

for {ELEMENT} in ${ARRAY[@]}; do [COMMAND_1]; [COMMAND_2]; [COMMAND_3]; done

在此Shell脚本中,我将列出服务器上可用的所有网络设备。
其中:我没有定义ARRAY,而是提供了带有*PATH,因此,在该PATH下的所有文件和目录都将被视为ARRAY'的ELEMENT`。

# for int in `ls /proc/sys/net/ipv4/conf/`;do echo "Interface: $int"; done
Interface: all
Interface: bond0
Interface: bond1
Interface: default
Interface: eth0
Interface: eth1
Interface: eth2
Interface: eth3
Interface: lo

在此脚本中,我将删除"/tmp"下与正则表达式" file *"匹配的所有文件。

# for file in /tmp/file*; do rm -vf $file; done
removed '/tmp/file1'
removed '/tmp/file2'
removed '/tmp/file3'