nl 命令详解与参数实测(Ubuntu 22.04)

nl 全参数实测:默认 -b t 跳空行、-b a/n、-n ln/rn/rz 对齐补零、-w 宽度、-s 分隔符、-b p 正则挑行、三区逻辑页与 -d 自定义、与 cat -n 差异,Ubuntu 22.04 实测。

Linux命令Linux系统UbuntuUbuntu 22.04命令行文本处理2026/10/15

nl 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 nl 的行号控制能力——默认 -b t 跳过空行编号、-b a/-b n 编号策略、-n ln/rn/rz 三种对齐格式、-w 行号宽度、-s 行号分隔符、-b p 正则挑选编号行、\:/\:\:/\:\:\: 三区逻辑页与 -d 自定义分隔符、与 cat -n 的差异,全部命令与回显已在 Ubuntu 22.04(nl 属 GNU coreutils 8.32)实测通过。

一、环境信息

本节记录实测环境与演示数据,便于读者对照复现。nl 与 cat -n 都能加行号,但 nl 的可调维度多得多——谁编号、怎么对齐、多宽、用什么分隔、按什么分区,全部可配。环境信息里同时列出演示目录与测试文件。

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • nl 版本:GNU coreutils 8.32(软件包 coreutils 8.32-4.1ubuntu1.4,见 2.3 实测)
  • 演示目录:/root/demo/nl/
  • 测试数据:含空行与数字行的 poem.txt(6 行,2 个空行)、三区结构文件 page.txt(含 \:\:\:/\:\:/\: 分隔行)、自定义分隔符文件 page2.txt(含 %: 行)

二、命令概览

2.1 语法与测试数据准备

帮助原文给出的语法是 nl [OPTION]... [FILE]...,职责一句话:Write each FILE to standard output, with line numbers added(输出文件内容并加行号)。nl 按「逻辑页」工作:一个文件可由分隔行切成 header(页眉)/ body(正文)/ footer(页脚)三区,各区可独立决定编号策略;帮助原文给出的默认参数是 -bt -d'\:' -fn -hn -i1 -l1 -n'rn' -s<TAB> -v1 -w6——即正文非空行编号、行号右对齐宽 6、编号后接制表符、从 1 起步。

准备演示数据——含空行与数字开头的 poem.txt、三区结构的 page.txt(heredoc 写入 \: 字面分隔行)、%: 分隔的 page2.txt:

cat > /root/demo/nl/poem.txt <<EOF
alpha line
bravo line

charlie line

delta line
123 numeric line
EOF
cat > /root/demo/nl/page.txt <<EOF
intro line
\:\:\:
header line
\:\:
body line
\:
footer line
EOF
printf "p1\n%%:\np2\n%%:\np3\n" > /root/demo/nl/page2.txt

用 cat -A 确认 page.txt 的分隔行是真实的 \:\:\:、\:\:、\: 三种字面行($ 表明各行以换行结尾):

$ cat -A /root/demo/nl/page.txt
intro line$
\:\:\:$
header line$
\:\:$
body line$
\:$
footer line$

验证数据就绪:

$ ls -l /root/demo/nl
total 12
-rw-r--r-- 1 root root 60 Oct 15 07:45 page.txt
-rw-r--r-- 1 root root 15 Oct 15 07:45 page2.txt
-rw-r--r-- 1 root root 65 Oct 15 07:45 poem.txt

2.2 --help 全量回显

nl 的参数覆盖编号策略、格式、宽度、分隔符、逻辑页,帮助原文完整收录:

Usage: nl [OPTION]... [FILE]...
Write each FILE to standard output, with line numbers added.

With no FILE, or when FILE is -, read standard input.

Mandatory arguments to long options are mandatory for short options too.
  -b, --body-numbering=STYLE      use STYLE for numbering body lines
  -d, --section-delimiter=CC      use CC for logical page delimiters
  -f, --footer-numbering=STYLE    use STYLE for numbering footer lines
  -h, --header-numbering=STYLE    use STYLE for numbering header lines
  -i, --line-increment=NUMBER     line number increment at each line
  -l, --join-blank-lines=NUMBER   group of NUMBER empty lines counted as one
  -n, --number-format=FORMAT      insert line numbers according to FORMAT
  -p, --no-renumber               do not reset line numbers for each section
  -s, --number-separator=STRING   add STRING after (possible) line number
  -v, --starting-line-number=NUMBER  first line number for each section
  -w, --number-width=NUMBER       use NUMBER columns for line numbers
      --help     display this help and exit
      --version  output version information and exit

Default options are: -bt -d'\:' -fn -hn -i1 -l1 -n'rn' -s<TAB> -v1 -w6

CC are two delimiter characters used to construct logical page delimiters;
a missing second character implies ':'.

STYLE is one of:

  a      number all lines
  t      number only nonempty lines
  n      number no lines
  pBRE   number only lines that contain a match for the basic regular
         expression, BRE

FORMAT is one of:

  ln     left justified, no leading zeros
  rn     right justified, no leading zeros
  rz     right justified, leading zeros


GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
Report any translation bugs to <https://translationproject.org/team/>
Full documentation <https://www.gnu.org/software/coreutils/nl>
or available locally via: info '(coreutils) nl invocation'

💡 说明:两个先划的重点——其一,STYLE 有四种(a 全编 / t 只编非空行 / n 不编 / pBRE 按正则挑行),-b/-h/-f 三区各配一份;其二,-d CC 的 CC 是两个分隔字符,帮助原文明确 "a missing second character implies ':'"(缺省第二字符补冒号),这条在 4.1 的 -d 实测里体现。

2.3 版本确认

确认 nl 的归属与版本:

$ nl --version | head -1
nl (GNU coreutils) 8.32

输出 nl (GNU coreutils) 8.32,即本文全部回显均来自 coreutils 8.32 的实现。

三、参数逐项实测

3.1 默认输出:-b t 跳过空行编号

先看 poem.txt 原始内容(6 行,其中第 3、5 行是空行,末行以数字开头):

$ cat /root/demo/nl/poem.txt
alpha line
bravo line

charlie line

delta line
123 numeric line

不带参数执行 nl(即默认 -b t,只给非空行编号):

$ nl /root/demo/nl/poem.txt
     1	alpha line
     2	bravo line
       
     3	charlie line
       
     4	delta line
     5	123 numeric line

三个观察点:其一,空行不占号——两行内容行之间隔着一个空行,号从 2 直接跳 3;其二,空行输出为 6 列空格(行号区宽度仍在,只是空白);其三,数字开头的 123 numeric line 照常编号为 5(它也是非空行)。默认的行号区宽 6、右对齐,编号后接一个制表符再接内容。

💡 提示:-b t 里的 t 取自 text(只编正文行),是排版行业「正文计数」的传统;要让空行也占号,见 3.2 的 -b a。

3.2 -b a 空行也编号 / -b n 全不编号

-b a(number all lines)给所有行编号,空行也占号:

$ nl -b a /root/demo/nl/poem.txt
     1	alpha line
     2	bravo line
     3	
     4	charlie line
     5	
     6	delta line
     7	123 numeric line

与 3.1 对比:同样的 6 行文件,这里编到 7——空行领走了 3 号和 5 号。-b n(number no lines)则全不编号,行号区输出等宽空格:

$ nl -b n /root/demo/nl/poem.txt
       alpha line
       bravo line
       
       charlie line
       
       delta line
       123 numeric line

行号区(6 列)被空格占据,内容整体右移。-b n 单看等价于「缩进版 cat」,但它的意义在组合:-h a -b n -f n 这类「各区不同策略」的搭配离不开 n 这个选项。

💡 提示:三种 STYLE 的记忆口诀——a=all、t=text(非空)、n=none;第四种 pBRE 见 3.6 实测。

3.3 -n ln/rn/rz:行号对齐与补零

-n FORMAT 控制行号的对齐方式,帮助原文列出三种。-n ln(左对齐、无前导零):

$ nl -n ln /root/demo/nl/poem.txt
1     	alpha line
2     	bravo line
       
3     	charlie line
       
4     	delta line
5     	123 numeric line

行号贴左、右侧补空格到 6 列。-n rn(右对齐、无前导零):

$ nl -n rn /root/demo/nl/poem.txt
     1	alpha line
     2	bravo line
       
     3	charlie line
       
     4	delta line
     5	123 numeric line

与 3.1 默认输出一致——帮助原文的默认参数里就写着 -n'rn'。-n rz(右对齐 + 前导零):

$ nl -n rz /root/demo/nl/poem.txt
000001	alpha line
000002	bravo line
       
000003	charlie line
       
000004	delta line
000005	123 numeric line

行号补足 6 位:000001~000005。三种格式覆盖了左对齐、右对齐、补零右对齐的全部组合,配合 -w 可进一步定宽。

💡 提示:rz 的补零格式适合与等宽日志对齐(000001 比 1 在等宽字体下更整齐),也便于按字典序排序行号字符串。

3.4 -w:行号区宽度

-w N 调整行号区列数。-n rz -w 3 把行号压到 3 列:

$ nl -n rz -w 3 /root/demo/nl/poem.txt
001	alpha line
002	bravo line
    
003	charlie line
    
004	delta line
005	123 numeric line

行号区从 6 列缩到 3 列,内容跟着左移。-n rn -w 1 极限压到 1 列(行号最大 5,够用):

$ nl -n rn -w 1 /root/demo/nl/poem.txt
1	alpha line
2	bravo line
  
3	charlie line
  
4	delta line
5	123 numeric line

1 列行号 + 制表符分隔。注意 -w 只影响行号区宽度,行号超出宽度时(如 -w 1 但有第 10 行)coreutils 会按实际位数输出,不会截断数字。

💡 提示:默认 6 列是为兼容传统打印分页(行号区 + 制表符 + 内容);日常终端展示 -w 3 -s ' ' 更紧凑,见 3.5。

3.5 -s:行号与内容的分隔符

默认行号后接制表符,-s STRING 换成任意字符串。-s " | ":

$ nl -s " | " /root/demo/nl/poem.txt
     1 | alpha line
     2 | bravo line
         
     3 | charlie line
         
     4 | delta line
     5 | 123 numeric line

行号、空格、竖线、内容依次排列,空行处也输出等宽的 | 区(5 列号区 + 分隔符)。换成 ") " 更像列表样式:

$ nl -s ") " /root/demo/nl/poem.txt
     1) alpha line
     2) bravo line
        
     3) charlie line
        
     4) delta line
     5) 123 numeric line

-s 与 -w 组合可以做出「紧凑行号列表」:nl -w 3 -s ' ' 即 3 列行号 + 单空格分隔。

💡 提示:-s 的字符串支持多字符(帮助原文:add STRING after line number);想把行号变成 1. 样式就用 -s ". "。

3.6 -b pBRE:按正则挑选编号行

STYLE 的第四种 pBRE:只有匹配基本正则的行才编号。给 -b 传 p^[[:alpha:]](只编以字母开头的行):

$ nl -b "p^[[:alpha:]]" /root/demo/nl/poem.txt
     1	alpha line
     2	bravo line
       
     3	charlie line
       
     4	delta line
       123 numeric line

对比 3.1 默认输出:前五行完全一致,唯一差异在末行——123 numeric line 以数字开头、不匹配 ^[[:alpha:]],行号区只输出空格。编号只在匹配行之间连续递增(1~5),未匹配行不打断序号。

💡 提示:-b p 常用于「只给代码行编号、跳过注释/空段」的排版需求;BRE 语法与 grep 默认一致,正则请整体作为一个参数传入(如上例的引号),避免 shell 展开干扰。

四、实战示例

4.1 逻辑页三区与 -d 自定义分隔符

nl 的独门机制是逻辑页:文件里的特殊分隔行把内容切成 header(页眉)/ body(正文)/ footer(页脚)三区,进入新区时编号自动从 -v 起点重新计。分隔行的字符对由 -d CC 定义,默认是 \:——帮助原文说明两个字符的三种组合:\:\:\: 开启 header、\:\: 开启 body、\: 开启 footer。

用准备好的 page.txt(结构见 2.1:intro line → \:\:\: → header line → \:\: → body line → \: → footer line)实测默认 nl:

$ nl /root/demo/nl/page.txt
     1	intro line

       header line

     1	body line

       footer line

逐行解读:intro line 在初始 body 区,编号 1;\:\:\: 分隔行本身输出为空行,其后的 header line 进入 header 区,默认 -h n 不编号(行号区输出空格);\:\: 后的 body line 进入新 body 区,编号重新从 1 计;\: 后的 footer line 进入 footer 区,默认 -f n 不编号。再用 -h a -f a 让页眉页脚也编号:

$ nl -h a -f a /root/demo/nl/page.txt
     1	intro line

     1	header line

     1	body line

     1	footer line

四行全部编号,且每区各自从 1 起——三区编号策略独立、页号独立重置,这是 cat -n 完全做不到的。再实测 -d 自定义分隔符:page2.txt 里 %: 是字面行,nl -d "%:" 把它定义为分隔符:

$ nl -d "%:" /root/demo/nl/page2.txt
     1	p1

       p2

       p3

p1 在初始 body 编号 1;第一个 %: 后进入 footer 区,p2、p3 默认 -f n 不编号——分隔符生效。对照组:-d "::" 定义 :: 为分隔符,page2.txt 里的 %: 只是普通内容行:

$ nl -d "::" /root/demo/nl/page2.txt
     1	p1
     2	%:
     3	p2
     4	%:
     5	p3

五行全部连续编号,%: 作为普通行领走 2、4 号。同时验证了帮助原文「缺省第二字符补冒号」的约定:-d "%:" 是完整两字符,若只写 -d "%" 则分隔符实为 %:(% 补上默认的 :)。

💡 提示:日常纯正文加行号用不到三区,但处理「多段文档、每段重新编号」时它就是为这个设计的;不想让编号分区重置,用 -p(do not reset line numbers for each section)。

4.2 与 cat -n 对照:谁该用谁

同一份 poem.txt,cat -n 的输出:

$ cat -n /root/demo/nl/poem.txt
     1	alpha line
     2	bravo line
     3	
     4	charlie line
     5	
     6	delta line
     7	123 numeric line

cat -n 给每一行编号(空行占 3、5 号),等价于 nl 的 cat -n 文件 ≈ nl -b a。把 nl 调成同样的编号策略与外观:

$ nl -b a -w 6 -s "  " /root/demo/nl/poem.txt
     1  alpha line
     2  bravo line
     3  
     4  charlie line
     5  
     6  delta line
     7  123 numeric line

两份输出几乎重合(差异仅分隔符:cat -n 用制表符,这里 -s " " 用两个空格)。

💡 技术拓展:「给行加号」的工具不止 cat -n 与 nl,常用对比如下——

方式原理/特点适用场景
cat -n所有输出行统一编号,空行占号,最快快速临时看行号
nl三区逻辑页 + 四种 STYLE + 格式/宽度/分隔符全可调排版级编号、跳空行、分段重编
grep -n只输出匹配行并带原文行号检索定位,不改动文本
less -N / vim :set nu查看器内显示行号,不落盘交互浏览时临时看号

关键差异:cat -n/nl 输出的是加了号的新文本(可进管道、可落盘),grep -n 报的是原始行号(用于定位),less/vim 的行号只显示不输出。本文实测采用 nl 做排版级编号——需要空行不占号、正则挑行、分区重编时它是唯一选项;纯临时看号用 cat -n 最省事。

五、注意事项与常见问题

Q1:nl 和 cat -n 到底差在哪? 两点:编号策略与分区机制。cat -n 恒等于「全行编号」;nl 默认 -b t 空行不占号(见 3.1/3.2 对照),还支持 -n/-w/-s 外观定制与 \: 三区逻辑页(见 4.1)。要 cat -n 的效果可用 nl -b a 复现(见 4.2)。

Q2:为什么 nl 输出里空行前有一段空格? 那是行号区:nl 对未编号的行也保留等宽的行号区(默认 6 列空格),保证内容列严格对齐(见 3.1/3.2 实测)。这是 nl 与「grep 加行号」类工具的显著区别。

Q3:-w 1 会把两位数行号截断吗? 不会。-w 设定行号区最小宽度,行号数字超宽时按实际位数输出,只影响对齐不影响数值。

Q4:-d "%" 为什么分隔符是 %: 而不是 %? 帮助原文约定:-d CC 需要两个字符,a missing second character implies ':'——只给一个字符时第二字符自动补为冒号(见 4.1 实测与对照)。

Q5:文件里恰好有 \: 字面内容的行被 nl 吃掉了? 是的,默认分隔符就是 \:,凡以 \:、\:\:、\:\:\: 开头的行都会被当作分区行处理(输出为空行)。冲突时用 -d 换一对不会出现的字符,或 `nl -d "::" 之类换符号(见 4.1 对照实测)。

Q6:nl 能从指定号数起步或改步长吗? 能。帮助原文列出的 -v N 设定每区起始号(默认 1)、-i N 设定步长(默认 1)、-l N 把连续 N 个空行计为一行(配合 -b a 使用)、-p 禁止分区重置。本文以默认起步与步长实测,其余参数按帮助原文同套语法使用。

六、参考链接