seq 命令是 Linux 文本处理和脚本编写中非常基础但容易被忽视的一个工具。它不会像 grep、awk 那样频繁出现在面试题里,但当你在 for 循环里需要生成 1 到 100 的数字、在性能测试里要构造一批有规律的 IP 或端口、或者想让输出对齐成等宽字符串时,seq 几乎是效率最高的选择。
这篇文章围绕 seq 命令展开,先说明它解决的问题,再逐步演示数值序列、步长控制、字符串格式化、与 xargs 和 for 循环配合的典型用法,最后给出参数速查、常见坑和面试中可能遇到的扩展场景。内容偏实践,命令都给出了可以直接复制的示例,方便在终端里验证。
1. seq 是什么,它解决什么问题
1.1 一句话理解 seq
seq 的全称是 sequence,作用是按照指定规则输出一串数字。最常用的是连续整数,比如 1 到 10,但步长、起始值、位数格式都可以自定义。
在脚本中,它最典型的替代场景是{1..10}这种大括号展开写法。大括号展开虽然简洁,但有局限性,比如无法直接用变量控制范围,而 seq 可以。
1.2 为什么需要单独学一个看起来这么简单的命令
写脚本时生成有规律的数字序列是高频操作。举几个实际场景:
- 批量创建文件
file_01.md到file_20.md。 - 循环提交 100 次请求测试接口稳定性。
- 生成一批待处理的端口号或 IP 末段。
- 构造测试数据,比如 1 到 1000 行的文本内容。
这些场景都可以用for循环加算术表达式实现,但代码会繁琐。seq 的优势是参数少、输出可控、支持格式化字符串,尤其在需要补零对齐时特别方便。
1.3 seq 的实际定位
seq 不是万能的,它只负责“生成序列”这一步。真正在脚本里产生价值,需要配合变量替换、xargs、循环和管道。
换句话说,seq 像是脚本工具箱里的一个基础零件。你不需要在所有场景里用它,但当你需要批量生成数字时,它比awk写循环更直观,比{1..n}更灵活。
2. seq 基本语法与三种调用方式
2.1 语法格式
seq [选项]... 尾数 seq [选项]... 首数 尾数 seq [选项]... 首数 步长 尾数三种形式分别对应:
- 只给一个参数:从 1 开始,输出到该参数结束。
- 给两个参数:从首数输出到尾数,默认步长为 1。
- 给三个参数:指定首数、步长和尾数。
尾数可以不大于首数,配合负数步长可以逆序生成。
2.2 最小示例
seq 5输出:
1 2 3 4 5等价于:
for i in {1..5}; do echo $i; done但 seq 的优点在于,起始值和结束值可以是变量:
start=3 end=8 seq $start $end输出:
3 4 5 6 7 82.3 指定首数和尾数
seq 3 6输出:
3 4 5 6注意,如果不指定步长,默认步长是 1。也就是说,seq 3 6等同于seq 3 1 6。
2.4 指定步长
seq 1 2 10输出:
1 3 5 7 9这里的步长是 2,因此生成了 1 到 10 内的所有奇数。
如果步长是小数:
seq 0 0.5 3输出:
0 0.5 1.0 1.5 2.0 2.5 3.0从这个例子能看出两个点:
- seq 支持小数步长。
- 小数参与计算时,输出格式可能带小数点,不一定有你期望的整数位数。
因此,涉及小数序列时,建议配合格式化参数一起使用。
2.5 逆序生成
seq 5 -1 1输出:
5 4 3 2 1逆序的规则是:起始值大于结束值,步长使用负数。
这里有一个隐藏细节:如果起始值大于结束值,但步长没有写成负数,seq 会直接结束,不会输出任何内容,也不报错。
seq 5 1这个命令没有任何输出,因为 seq 发现 5 大于 1,而默认步长是 1,继续生成会超出范围。
写脚本时,如果逆序和正序可能交替出现,建议先判断大小,再显式指定步长。
3. seq 的格式化输出与补零处理
3.1 使用 -w 实现等宽输出
等宽输出是最常见的需求。比如生成 001 到 010,直接用默认输出是做不到的:
seq 10输出是:
1 2 ... 10位数不齐,排序和拼接文件名时都会出问题。
使用-w参数:
seq -w 1 10输出:
01 02 03 04 05 06 07 08 09 10-w会自动根据最大数值的位数,对所有输出补齐前导零。
如果需要三位数对齐:
seq -w 1 100输出效果类似:
001 002 ... 099 1003.2 使用 -f 自定义格式
-f参数允许使用 printf 风格的格式字符串,控制输出的模板。常见占位符包括:
%g:按数值大小自动决定是否显示小数,通常用于整数。%d:整数。%e:科学计数法。%f:浮点数。%03g:至少占 3 位,不足补零。
seq -f "%03g" 1 10输出:
001 002 ... 009 010这与-w的效果相似,但-f更灵活,可以自由添加前后缀。
3.3 给序列添加前缀或后缀
实际项目中,需要的是带有前缀的文件名或字符串,而不仅仅是数字。比如批量生成log_01.txt到log_05.txt:
seq -f "log_%02g.txt" 1 5输出:
log_01.txt log_02.txt log_03.txt log_04.txt log_05.txt这个写法背后使用的是 printf 的格式字符串,%02g表示至少占两位、不足补零。
同样可以添加后缀:
seq -f "%g.md" 1 3输出:
1.md 2.md 3.md3.4 双变量循环的替代方案
seq 的一个好处是:可以用一个命令生成两个不同格式的序列,然后通过粘贴组合。
paste <(seq -f "node-%02g" 1 3) <(seq -f "port-%d" 8001 8003)输出:
node-01 port-8001 node-02 port-8002 node-03 port-8003在脚本中这种写法可以快速生成配置矩阵。
4. seq 指定分隔符与批量构造参数
4.1 默认分隔符是换行
默认情况下,seq 每个数字单独一行。这在大多数场景下符合预期,因为 for 循环和 while 读取都按行处理。
4.2 使用 -s 指定分隔符
有时需要将序列合并成一行,用空格或逗号分隔。此时使用-s:
seq -s " " 1 5输出:
1 2 3 4 5用逗号:
seq -s "," 1 5输出:
1,2,3,4,5这在构造批量参数、SQL 批量 values、JSON 数组元素时很有用。
例如拼接一段 JSON 数组中的数字:
echo "[$(seq -s "," 1 5)]"输出:
[1,2,3,4,5]4.3 结合 xargs 批量执行命令
seq 最常见的生产用法之一,是配合 xargs 实现批量命令:
seq 1 5 | xargs -I {} echo "handle-{}"输出:
handle-1 handle-2 handle-3 handle-4 handle-5如果要并行执行,使用 xargs 的-P参数:
seq 1 10 | xargs -P 4 -I {} curl -s http://example.com/api/test/{}这里的思路是:先用 seq 生成编号,再由 xargs 控制并发数和命令模板。相比for循环,这种写法可以更方便地限制并发数。
4.4 seq 配合 for 循环
在 Bash 中,for 循环配合 seq 可以动态控制范围:
for i in $(seq -w 1 10); do echo "file_${i}.log" done输出:
file_01.log file_02.log ... file_10.log注意,$(seq ...)命令替换会先把所有输出加载到内存,然后再进行词分割。如果生成的序列特别大,比如百万级,内存占用会明显上升。此时可以直接用 C 风格 for 循环,或改用for ((i=1; i<=1000000; i++))。
5. seq 的边界行为与容易踩的坑
5.1 错误的范围不报错,但也不输出
seq 5 1这段命令不会报错,也不会输出任何数字。原因是默认步长为 1,从 5 开始大于 1,继续输出会越界。
很多新手踩坑后第一反应是检查语法,但问题在步长方向。使用时要注意:如果首数大于尾数,必须显式传负数步长。
5.2 小数运算精度问题
seq 支持小数,但浮点计算存在精度问题。例如:
seq 0.1 0.1 0.5输出:
0.1 0.2 0.3 0.4 0.5表面上看起来正常,但某些组合可能输出意外的 0.30000000000000004 之类的值,这是因为底层浮点表示导致。实际使用中,如果计算结果用于精确比较或文件命名,建议不要依赖小数序列。
5.3 seq 与 Bash 内置的大括号展开选择问题
大括号展开:
echo {1..10}输出:
1 2 3 4 5 6 7 8 9 10这行写法在 Bash 中同样常见。但大括号展开无法直接使用变量:
n=10 echo {1..$n}输出:
{1..10}它不会展开成数字 1 到 10。
如果范围是动态的,使用 seq 更可靠:
n=10 seq 1 $n所以在脚本中,只要范围依赖变量,推荐使用 seq。
5.4 seq 的输出默认没有结束符问题
默认每个数字一个换行,最后一个数字也有换行。当使用-s指定分隔符时,最后一个数字后面仍然有换行。如果不需要尾部换行,可以使用printf处理,或使用命令替换去掉尾部空白。
例如:
printf "%s" "$(seq -s ',' 1 5)"输出:
1,2,3,4,5之后可以继续拼接其他字符串。
5.5 百万级序列的性能问题
如果生成非常大的序列,seq 本身效率不低,但命令替换和管道可能成为瓶颈。一个常见观点是:对于 10 万以内的序列,seq 简洁直观;对于百万级甚至更高的循环,直接在脚本里用for ((i=1; i<=n; i++))更合适,因为避免生成一个超大临时字符串或管道数据。
性能对比可以这样测:
time seq 1 1000000 > /dev/null和
time for ((i=1; i<=1000000; i++)); do :; done不同机器差异明显,但在脚本中,选择哪种写法还取决于是否真的需要“先生成完整序列再消费”。
6. seq 参数速查表与典型场景对照
6.1 参数速查表
| 选项 | 作用 | 示例 | 说明 |
|---|---|---|---|
-w | 等宽自动补零 | seq -w 1 10 | 输出 01 到 10 |
-f | 自定义 printf 格式 | seq -f "%03g" 1 5 | 输出 001 到 005 |
-s | 指定分隔符 | seq -s "," 1 3 | 输出 1,2,3 |
| 无参数 | 默认换行输出 | seq 1 3 | 每个数字一行 |
格式串常用占位符:
| 占位符 | 含义 | 示例输出 |
|---|---|---|
%g | 普通数字 | seq -f "%g" 1 2输出 1 2 |
%03g | 至少 3 位,补零 | seq -f "%03g" 1 2输出 001 002 |
%.2f | 保留两位小数 | seq -f "%.2f" 1 2输出 1.00 2.00 |
%d | 整数 | seq -f "num%d" 1 2输出 num1 num2 |
6.2 常见应用对照表
| 需求 | 推荐命令 |
|---|---|
| 生成 1 到 100 的连续整数 | seq 1 100 |
| 生成 01 到 20 的补零编号 | seq -w 1 20 |
| 生成带前缀的文件名 | seq -f "log_%02g.txt" 1 5 |
| 生成 1 到 10 的偶数 | seq 2 2 10 |
| 生成 5 到 1 的逆序 | seq 5 -1 1 |
| 生成逗号分隔的数字串 | seq -s "," 1 5 |
| 批量处理编号参数 | seq 1 10 | xargs -I {} cmd {} |
7. 与常用命令组合的实战案例
7.1 批量创建文件夹
for i in $(seq -w 1 12); do mkdir -p "2024-$(printf "%s" $i)" done说明:生成 01 到 12 的月份编号,创建如 2024-01、2024-02 这样的目录。
7.2 提交批量测试请求
seq 1 5 | xargs -I {} curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/api/test/{}说明:模拟带路径参数的请求,并输出 HTTP 状态码。-o /dev/null丢弃响应体,-w输出格式化信息。
7.3 生成 SQL 批量插入语句
seq 1 5 | sed 's/^/(/; s/$/, '"'"'user'"'"'),/' | sed '1i INSERT INTO users (id, name) VALUES'输出类似:
INSERT INTO users (id, name) VALUES (1, 'user'), (2, 'user'), ... (5, 'user'),更干净的写法是使用 awk 组合,但上面命令足以说明 seq 作为“编号发生器”在文本处理中的位置。实际生产中可以结合paste和模板文件,生成多列数据。
7.4 数字倒计时脚本
seq 10 -1 1 | while read i; do echo "$i 秒后开始执行" sleep 1 done这种方式比 C 风格循环更容易阅读,且 seq 已经负责生成“由大到小”的编号序列。
7.5 生成随机端口段
base=8500 seq 0 4 | awk -v b="$base" '{print b + $1 * 10}'输出:
8500 8510 8520 8530 8540用于生成一组间隔固定的端口号,适合测试环境分配端口。
8. seq 在生产脚本中的最佳实践
8.1 优先用 seq,而不是手写 while 循环计数器
很多初学者写循环时习惯这样:
i=1 while [ $i -le 10 ] do echo $i i=$((i + 1)) done这种写法没有问题,但代码更长,变量多了容易出错。如果只是生成一个编号列表,seq 更直接。
8.2 范围依赖变量时不要用大括号展开
Bash 的{1..10}不支持变量范围,除非使用间接展开或 eval。虽然可以用,但 eval 会增加安全性风险。项目脚本中,只要范围来自用户输入或配置文件,建议使用 seq。
8.3 注意与 while 循环配合时的子 shell 问题
管道会启动子 shell。比如:
seq 1 3 | while read i; do count=$((count + 1)) done echo $count这里的count在管道子 shell 中修改,父 shell 读不到结果。
如果需要保留循环中的变量,使用进程替换:
while read i; do count=$((count + 1)) done < <(seq 1 3) echo $count这种方式可以避免子 shell,计数结果保留在当前 shell 中。
8.4 指定语言环境避免输出异常
某些老版本 seq 或特定 locale 下,浮点数可能使用逗号作为小数点。对于脚本拼接字符串的场景,建议显式指定:
LC_ALL=C seq 0 0.5 2这样可以确保小数点是点,而不是逗号,避免后续解析出错。
8.5 在脚本开头统一处理范围变量
实战脚本中,seq 的参数往往来自用户输入。建议在脚本开头统一做范围校验:
start=1 end=100 step=2 # 校验范围合法性 if [ "$end" -lt "$start" ] && [ "$step" -gt 0 ]; then echo "错误:end 小于 start 时,step 必须为负数" >&2 exit 1 fi seq "$start" "$step" "$end"这样使用 seq 时不容易因为“范围方向错误”而静默无输出。
8.6 避免在超大规模场景滥用命令替换
for i in $(seq 1 1000000); do ... done这种写法会先产生一个占用内存的大字符串,再完成单词拆分。如果循环体内逻辑不多,直接用 C 风格 for 会更节省资源:
for ((i=1; i<=1000000; i++)); do ... done判断标准:如果序列只是用于循环计数,不需要参与管道或文件生成,选择 C 风格 for;如果序列要传递给其他命令,比如 xargs,可以使用 seq。
9. 面试与学习复盘中如何理解 seq
9.1 高频问法
面试或技术复盘中,seq 经常以这样的问题出现:
- “Linux 下如何生成 1 到 100 的整数序列?”
- “如何生成 001 到 100 的编号?”
- “seq 和
{1..10}有什么区别?” - “seq 能否生成小数序列?”
对应的回答要点:
- 生成整数序列:
seq 1 100。 - 生成补零编号:
seq -w 1 100或seq -f "%03g" 1 100。 - 与
{1..10}的区别:seq 支持变量、小数、步长和格式化字符串,而大括号展开在变量范围上受限。 - 支持小数序列:
seq 0 0.1 1。
9.2 学习建议
最有效的练习方式是设计几个组合场景:
- 先用 seq 生成编号序列。
- 再配合 xargs 批量创建文件。
- 再配合 sed 或 awk 生成格式化文本。
- 再配合 while 循环处理需要保留状态的逻辑。
这一套下来,seq 的定位就不只是“生成数字”,而是整个文本处理管道的一部分。
10. 配套练习与扩展方向
10.1 练习题
- 生成 1 到 50 的所有奇数。
- 生成 001 到 030 的等宽编号。
- 生成
2024_01.log到2024_12.log的文件名。 - 使用 seq 和 xargs 并发执行 10 次测试命令。
- 将 1 到 5 拼接成
1,2,3,4,5字符串。
答案参考:
seq 1 2 50 seq -w 1 30 seq -f "2024_%02g.log" 1 12 seq 1 10 | xargs -P 4 -I {} echo "run {}" seq -s "," 1 510.2 扩展方向
学习 seq 之后,可以往以下方向扩展:
- 深入
{start..end}大括号展开的语法边界。 - 结合
xargs -P理解并行任务调度。 - 学习 awk 的数值生成能力,用于更复杂的编号规则。
- 学习 printf 的格式字符串,这是理解
-f参数的基础。 - 探索 shell 内置
for ((...))与外部命令 seq 在性能和应用场景上的差异。
这些内容在 Linux 脚本编程中都属于基础但高频使用的能力。
seq 命令并不复杂,真正需要花时间的是在实战中判断“什么时候用它、什么时候用循环、什么时候用大括号展开”。当你形成这套判断后,写脚本会明显更顺手,排查问题也更容易定位到环节。