Files
bash-tutorial/docs/loop.md
2020-03-16 20:24:39 +08:00

7.5 KiB
Raw Blame History

循环

Bash 提供三种循环语法forwhileuntil

while 循环

while循环有一个判断条件,只要符合条件,就不断循环执行指定的语句。

while condition; do
  statements
done

上面代码中,只要满足条件condition,就会执行命令statements。然后,再次判断是否满足条件condition,只要满足,就会一直执行下去。只有不满足条件,才会退出循环。

循环条件condition可以使用test命令,跟if语句的判断条件一致。

#!/bin/bash

number=0
while [ "$number" -lt 10 ]; do
  echo "Number = $number"
  number=$((number + 1))
done

上面例子中,只要变量number小于10就会不断加1直到number等于10然后退出循环。

关键字do可以跟while不在同一行,这时两者之间不需要使用分号分隔。

while true
do
  echo 'Hi, while looping ...';
done

上面的例子会无限循环,可以按下 Ctrl + c 停止。

while循环写成一行,也是可以的。

$ while true; do echo 'Hi, while looping ...'; done

while的条件部分也可以是执行一个命令。

$ while echo 'ECHO'; do echo 'Hi, while looping ...'; done

上面例子中,判断条件是echo 'ECHO'。由于这个命令总是执行成功,所以上面命令会产生无限循环。

while的条件部分可以执行任意数量的命令,但是执行结果的真伪只看最后一个命令的执行结果。

$ while true; false; do echo 'Hi, looping ...'; done

上面代码运行后,不会有任何结果,因为while的最后一个命令是false

breakcontinue

Bash 提供了两个内部命令,用来在循环内部跳出循环。

break命令立即终止循环,程序继续执行循环之后的语句,即不再执行剩下的循环。

continue命令立即终止本轮循环,开始执行下一轮循环。

until 循环

until循环与while循环恰好相反,只要不符合判断条件(判断条件失败),就不断循环执行指定的语句。一旦符合判断条件,就退出循环。

until condition; do
  commands
done

判断条件condition可以使用test命令,跟if语句的判断一致。

关键字do可以与until不写在同一行,这时两者之间不需要分号分隔。

until condition
do
  commands
done

下面是一个例子。

$ until false; do echo 'Hi, until looping ...'; done
Hi, until looping ...
Hi, until looping ...
Hi, until looping ...
^C

上面代码中,until的部分一直为false,导致命令无限运行,必须按下 Ctrl + c 终止。

#!/bin/bash

number=0
until [ "$number" -ge 10 ]; do
  echo "Number = $number"
  number=$((number + 1))
done

上面例子中,只要变量number小于10就会不断加1直到number大于等于10就退出循环。

until的条件部分也可以是一个命令,表示在这个命令执行成功之前,不断重复尝试。

until cp $1 $2; do
  echo 'Attempt to copy failed. waiting...'
  sleep 5
done

上面例子表示,只要cp $1 $2这个命令执行不成功就5分钟后再尝试一次直到成功为止。

until循环都可以转为while循环,只要把条件设为否定即可。上面这个例子可以改写如下。

while ! cp $1 $2; do
  echo 'Attempt to copy failed. waiting...'
  sleep 5
done

一般来说,until用得比较少,完全可以统一都使用while

for...in 循环

for...in循环用于遍历列表的每一项。

for variable in list
do
  commands
done

上面语法中,for循环会依次从list列表中取出一项,作为变量variable,然后在循环体中进行处理。

关键词do可以跟for写在同一行,两者使用分号分隔。

for variable in list; do
  commands
done

下面是一个例子。

#!/bin/bash

for i in word1 word2 word3; do
  echo $i
done

上面例子中,word1 word2 word3是一个包含三个单词的列表,变量i依次等于word1word2word3,命令echo $i则会相应地执行三次。

列表可以由通配符产生。

for i in *.png; do
  ls -l $i
done

上面例子中,*.png会替换成当前目录中所有 PNG 图片文件,变量i会依次等于每一个文件。

列表也可以通过子命令产生。

#!/bin/bash

count=0
for i in $(cat ~/.bash_profile); do
  count=$((count + 1))
  echo "Word $count ($i) contains $(echo -n $i | wc -c) characters"
done

上面例子中,cat ~/.bash_profile命令会输出~/.bash_profile文件的内容,然后通过遍历每一个词,计算该文件一共包含多少个词,以及每个词有多少个字符。

in list的部分可以省略,这时list默认等于脚本的所有参数$@。但是,为了可读性,最好还是不要省略,参考下面的例子。

for filename; do
  echo "$filename"
done

# 等同于

for filename in "$@" ; do
  echo "$filename"
done

for 循环

for循环还支持 C 语言的循环语法。

for (( expression1; expression2; expression3 )); do
  commands
done

上面代码中,expression1用来初始化循环条件,expression2用来决定循环结束的条件,expression3在每次循环迭代的末尾执行,用于更新值。

它等同于下面的while循环。

(( expression1 ))
while (( expression2 )); do
    commands
    (( expression3 ))
done

下面是一个例子。

for (( i=0; i<5; i=i+1 )); do
  echo $i
done

上面代码中,初始化变量i的值为0循环执行的条件是i小于5。每次循环迭代结束时i的值加1。

for条件部分的三个语句,都可以省略。

for ((;;))
do
  read var
  if [ "$var" = "." ]; then
    break
  fi
done

上面脚本会反复读取命令行输入,直到用户输入了一个点(.)位为止,才会跳出循环。

select 结构

select结构主要用来生成简单的菜单。它的语法与for...in循环基本一致。

select name
[in list]
do
  commands
done

Bash 会对select依次进行下面的处理。

  1. select生成一个菜单,内容是列表list的每一项,并且每一项前面还有一个数字编号。
  2. Bash 提示用户选择一项,输入它的编号。
  3. 用户输入以后Bash 会将该项的内容存在变量name,该项的编号存入环境变量REPLY。如果用户没有输入就按回车键Bash 会重新输出菜单,让用户选择。
  4. 执行命令体commands
  5. 执行结束后,回到第一步,重复这个过程。

下面是一个例子。

select brand in Samsung Sony iphone symphony Walton
do
  echo "You have chosen $brand"
done

上面例子中Bash 会让用户选择一个列出的品牌,然后将其打印出来。并且不断重复这个过程,直到用户按下Ctrl + c,退出执行。

select可以与case结合,针对不同项,执行不同的命令。

#!/bin/bash
echo "Which Operating System do you like?"

select os in Ubuntu LinuxMint Windows8 Windows7 WindowsXP
do
  case $os in
    "Ubuntu"|"LinuxMint")
      echo "I also use $os."
    ;;
    "Windows8" | "Windows10" | "WindowsXP")
      echo "Why don't you try Linux?"
    ;;
    *)
      echo "Invalid entry."
      break
    ;;
  esac
done

上面例子中,case针对用户选择的不同项,执行不同的命令。

参考链接