跳至内容

Bash - 循环


目标:在本章中,您将学会如何

✔ 使用循环;

🏁 linux, 脚本, bash, 循环

知识⭐ ⭐
复杂性: ⭐ ⭐ ⭐

阅读时间: 20 分钟


bash shell 允许使用 **循环**。这些结构允许根据静态定义的值、动态值或条件 **多次**(从 0 到无穷大)执行 **一系列命令**。

  • while
  • until
  • for
  • select

无论使用哪种循环,要重复执行的命令都放在 **`do` 和 `done` 关键字之间**。

while 条件循环结构

`while` / `do` / `done` 结构会评估 `while` 后面跟随的命令。

如果该命令为真(`$? = 0`),则执行 `do` 和 `done` 之间的命令。然后脚本返回到开头再次评估该命令。

当评估的命令为假(`$? != 0`)时,shell 会在 `done` 之后的第一个命令处恢复脚本的执行。

`while` 条件循环结构的语法

while command
do
  command if $? = 0
done

使用 `while` 条件结构的示例

while [[ -e /etc/passwd ]]
do
  echo "The file exists"
done

如果评估的命令不发生变化,循环将是无限的,shell 将永远不会执行脚本后面的命令。这可能是故意的,但也可能是一个错误。所以你必须 **非常小心管理循环的命令,并找到一种方法来跳出循环**。

要跳出 `while` 循环,你必须确保被评估的命令不再为真,而这并非总是可能的。

有一些命令允许你改变循环的行为

  • exit
  • break
  • continue

exit 命令

`exit` 命令会终止脚本的执行。

`exit` 命令的语法

exit [n]

使用 `exit` 命令的示例

bash # to avoid being disconnected after the "exit 1
exit 1
echo $?
1

`exit` 命令会立即终止脚本。可以通过给出参数(从 `0` 到 `255`)来指定脚本的返回码。如果没有给出参数,脚本的最后一个命令的返回码将被传递给 `$?` 变量。

`break` / `continue` 命令

`break` 命令允许你通过跳到 `done` 之后的第一个命令来中断循环。

`continue` 命令允许你通过返回到 `done` 之后的第一个命令来重新开始循环。

while [[ -d / ]]                                                   INT   17s do
  echo "Do you want to continue? (yes/no)"
  read ans
  [[ $ans = "yes" ]] && continue
  [[ $ans = "no" ]] && break
done

`true` / `false` 命令

`true` 命令总是返回 `true`,而 `false` 命令总是返回 `false`。

true
echo $?
0
false
echo $?
1

将它们用作循环的条件,可以实现无限循环的执行,或者禁用该循环。

示例

while true
do
  echo "Do you want to continue? (yes/no)"
  read ans
  [[ $ans = "yes" ]] && continue
  [[ $ans = "no" ]] && break
done

until 条件循环结构

`until` / `do` / `done` 结构会评估 `until` 后面跟随的命令。

如果该命令为假(`$? != 0`),则执行 `do` 和 `done` 之间的命令。然后脚本返回到开头再次评估该命令。

当评估的命令为真(`$? = 0`)时,shell 会在 `done` 之后的第一个命令处恢复脚本的执行。

`until` 条件循环结构的语法

until command
do
  command if $? != 0
done

`until` 条件结构使用的示例

until [[ -e test_until ]]
do
  echo "The file does not exist"
  touch test_until
done

select 替代选择结构

`select` / `do` / `done` 结构允许显示一个包含多个选项的菜单并请求输入。

列表中的每个项目都有一个编号选项。当你输入一个选择时,所选的值将被赋给 `select` 之后(为此目的创建)的变量。

然后它会执行 `do` 和 `done` 之间的命令,并使用这个值。

  • 变量 `PS3` 包含输入选择的提示;
  • 变量 `REPLY` 将返回选择的编号。

需要 `break` 命令来退出循环。

注意

`select` 结构对于小型简单的菜单非常有用。要自定义更完整的显示,必须在 `while` 循环中使用 `echo` 和 `read` 命令。

`select` 条件循环结构的语法

PS3="Your choice:"
select variable in var1 var2 var3
do
  commands
done

`select` 条件结构使用的示例

PS3="Your choice: "
select choice in coffee tea chocolate
do
  echo "You have chosen the $REPLY: $choice"
done

如果运行此脚本,它会显示类似这样的内容

1) Coffee
2) Tea
3) Chocolate
Your choice : 2
You have chosen choice 2: Tea
Your choice:

for 值列表循环结构

`for` / `do` / `done` 结构会将列表的第一个元素赋给 `for` 之后(为此目的创建)的变量。然后它会执行 `do` 和 `done` 之间的命令,并使用这个值。然后脚本返回到开头,将列表的下一个元素赋给工作变量。当最后一个元素被使用后,shell 会在 `done` 之后的第一个命令处恢复执行。

`for` 值列表循环结构的语法

for variable in list
do
  commands
done

`for` 条件结构使用的示例

for file in /home /etc/passwd /root/fic.txt
do
  file $file
done

任何产生值列表的命令都可以放在 `in` 之后,使用子执行。

  • 当 `IFS` 变量包含 `$' \t\n'` 时,`for` 循环将把该命令结果的 **每个单词** 作为要循环的元素列表。
  • 当 `IFS` 变量包含 `$' \t\n'`(即没有空格)时,`for` 循环将读取该命令结果的每一行。

这可能是目录中的文件。在这种情况下,变量将取文件名中的每个单词作为值。

for file in $(ls -d /tmp/*)
do
  echo $file
done

这可以是一个文件。在这种情况下,变量将取浏览文件时包含的每个单词作为值,从开始到结束。

cat my_file.txt
first line
second line
third line
for LINE in $(cat my_file.txt); do echo $LINE; done
first
line
second
line
third line
line

要逐行读取文件,必须修改 `IFS` 环境变量的值。

IFS=$'\t\n'
for LINE in $(cat my_file.txt); do echo $LINE; done
first line
second line
third line

作者:Antoine Le Morvan

贡献者:Steven Spencer, Ganna Zhyrnova