Bash 序列表达式通过定义起始点和结束点来生成一系列整数或字符。它最常用于 for 循环中,用于遍历数字或字母范围,而无需手动写出每个值。

本指南涵盖了序列表达式的语法、步长增量、零填充、字符范围、实用的循环示例,以及如何结合变量使用动态范围。

Bash 序列表达式语法

序列表达式采用以下形式:

{START..END[..INCREMENT]}
  • 表达式以左花括号开始,以右花括号结束。
  • START 和 END 可以是正整数或单个字符。
  • START 和 END 的值是必需的,并且由两个点 .. 分隔,中间不能有空格。
  • INCREMENT(增量)值是可选的。如果存在,它必须与 END 值之间用两个点 .. 分隔,且中间不能有空格。
  • 表达式会展开为 START 和 END 之间的每个数字或字符,包括提供的起止值。
  • 格式错误的表达式将保持原样不变。

整数范围

以下是该表达式的实际效果——生成从 0 到 3 的范围:

echo {0..3}
0 1 2 3

如果 START 大于 END,表达式将创建一个递减的范围:

echo {3..0}
3 2 1 0

字符范围

序列表达式也可以用于单个字符。以下示例打印小写字母表:

echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z

当提供字符时,表达式按字典序展开。你也可以使用大写字母:

echo {a..z}

增量和步长

当给定 INCREMENT(增量)时,它会设置每个生成值之间的步长:

for i in {0..20..5}
do
  echo "Number: $i"
done
Number: 0
Number: 5
Number: 10
Number: 15
Number: 20

你可以使用负增量来实现向下步进:

for i in {10..0..2}
do
  echo "Number: $i"
done
Number: 10
Number: 8
Number: 6
Number: 4
Number: 2
Number: 0

前导零

在使用整数时,你可以通过在 START 或 END 前添加前导零来强制每个数字具有相同的宽度:

for i in {00..5}
do
  echo "Number: $i"
done
Number: 00
Number: 01
Number: 02
Number: 03
Number: 04
Number: 05

前缀和后缀

表达式可以与花括号前后静态文本组合使用:

echo file{01..4}.txt
file01.txt file02.txt file03.txt file04.txt

这对于生成文件名、目录名或任何包含数字后缀的模式非常有用。

在 for 循环中使用范围

序列表达式最常用于 for 循环。以下示例从 1 迭代到 5 并打印每个值:

如果你在寻找 Python 中 for i in range(...) 的 Bash 等效写法,对于固定范围,花括号展开是最简单的选择。

for i in {1..5}
do
  echo "Iteration: $i"
done
Iteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
Iteration: 5

一个常见的用例是创建一组编号目录:

for i in {1..5}
do
  mkdir "backup_$i"
done

这将在当前目录中创建 backup_1 到 backup_5。

使用 seq 处理变量范围

一个常见的混淆点是 Bash 不会在花括号表达式内部展开变量。如果你尝试将变量用作 START 或 END,花括号表达式将保持未展开状态:

START=1
END=5
echo {$START..$END}
{1..5}

输出的是字面字符串 {1..5},而不是展开后的范围。这是 Bash 的限制——花括号展开发生在变量替换之前。

要使用动态范围,请改用 seq 命令:

START=1
END=5
for i in $(seq $START $END)
do
  echo "Number: $i"
done
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5

seq 也接受步长参数:

for i in $(seq 0 2 10)
do
  echo "Number: $i"
done
Number: 0
Number: 2
Number: 4
Number: 6
Number: 8
Number: 10

处理变量范围的另一个选项是 C 风格的 for 循环,它直接支持变量:

START=1
END=5
for ((i=START; i<=END; i++))
do
  echo "Number: $i"
done

seq 和 C 风格循环都能可靠地与变量一起工作。请选择在你的脚本中可读性更好的那一种。

实用示例

倒计时器

for i in {10..1}
do
  echo "$i..."
  sleep 1
done
echo "Done"

生成测试文件

for i in {1..10}
do
  touch "testfile_${i}.log"
done

按列打印字母表

for c in {a..z}
do
  printf "%s " "$c"
done
echo

创建编号备份

for i in {01..07}
do
  cp config.conf "config_backup_${i}.conf"
done

快速参考

表达式结果
{1..5}1 2 3 4 5
{5..1}5 4 3 2 1
{0..10..2}0 2 4 6 8 10
{01..04}01 02 03 04(零填充)
{a..e}a b c d e
{A..E}A B C D E
file{1..3}.txtfile1.txt file2.txt file3.txt
seq $START $END使用变量的动态整数范围
seq $START $STEP $END带步长的动态范围

常见问题解答

为什么 {$START..$END} 不起作用?
Bash 中的花括号展开发生在变量替换之前,因此 {$START..$END} 被视为字面字符串而不是范围。请在命令替换中使用 seq $START $END,或者改用 C 风格的 for ((i=START; i<=END; i++)) 循环。

{1..5} 和 seq 1 5 有什么区别?
{1..5} 是纯 Bash 花括号展开——速度快且无外部命令。seq 1 5 是一个外部命令,它将数字打印到标准输出,每行一个。主要的实际区别在于,花括号展开不支持变量,而 seq 支持。

我可以使用长度超过一个字符的字符串配合序列表达式吗?
不可以。序列表达式仅支持单个字符或整数。对于多字符字符串,你需要采用不同的方法,例如数组或对列表进行循环。

如何创建反向或倒计时范围?
将 START 设置为高于 END:{5..1}。如果使用增量,可以使用 {10..0..2} 以步长 2 向下步进。

我可以在 for 循环之外使用序列表达式吗?
可以。echo {1..5} 会在单行上以空格分隔的方式打印展开后的值。你还可以在命令参数、文件通配符或 Bash 执行花括号展开的任何地方使用它——例如 mkdir dir{1..5} 可以一次性创建五个目录。