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

tr 命令逐参数实测:大小写区间与字符类、-d 删除、-s 压缩、-c 补集及 -cs 组合,只读 stdin 与无正则两大限制,全部回显在 Ubuntu 22.04(GNU coreutils 8.32)实测通过。

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

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

目标:全面掌握 GNU tr 的字符转换能力——大小写区间与字符类两种写法、-d 删除、-s 压缩重复、-c 补集及 -cs 组合,以及「只读标准输入、不支持文件参数与正则」两大限制,全部命令与回显已在 Ubuntu 22.04(GNU coreutils 8.32)实测通过。

一、环境信息

本节记录实测环境与测试数据,便于读者按相同条件复现本文全部命令与回显。

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • tr 版本:GNU coreutils 8.32(tr --version 实测)
  • 默认 locale:LANG 未设置(等效 C locale)
  • 实测工作目录:/root/demo/tr/
  • 测试数据:words.txt(2 行英文样例,用于文件参数报错演示);其余演示通过 echo/printf 管道提供输入

二、命令概览

2.1 语法与测试数据准备

tr 的基本语法为 tr [OPTION]... SET1 [SET2]:从标准输入读取数据,把 SET1 中的字符按位置映射为 SET2 中的字符(转换),或按选项删除、压缩字符,结果写到标准输出。它不接受文件参数,只吃管道或重定向。准备一个英文样例文件供后文报错演示使用:

mkdir -p /root/demo/tr

cat > /root/demo/tr/words.txt <<'EOF'
Hello World
Linux Text Processing
EOF

验证数据就绪:

$ ls -l /root/demo/tr
total 4
-rw-r--r-- 1 root root 34 Oct 15 07:40 words.txt

$ cat /root/demo/tr/words.txt
Hello World
Linux Text Processing

💡 说明:tr 的绝大多数用法输入都是短文本,本文统一用 echo/printf 管道实测,输出即回显;words.txt 只在 3.6 节演示「传文件参数会报错」。

2.2 --help 全量回显

tr --help 输出用法与全部可解释序列(实测原样保留,可作为字符集写法速查):

Usage: tr [OPTION]... SET1 [SET2]
Translate, squeeze, and/or delete characters from standard input,
writing to standard output.

  -c, -C, --complement    use the complement of SET1
  -d, --delete            delete characters in SET1, do not translate
  -s, --squeeze-repeats   replace each sequence of a repeated character
                            that is listed in the last specified SET,
                            with a single occurrence of that character
  -t, --truncate-set1     first truncate SET1 to length of SET2
      --help     display this help and exit
      --version  output version information and exit

SETs are specified as strings of characters.  Most represent themselves.
Interpreted sequences are:

  \NNN            character with octal value NNN (1 to 3 octal digits)
  \\              backslash
  \a              audible BEL
  \b              backspace
  \f              form feed
  \n              new line
  \r              return
  \t              horizontal tab
  \v              vertical tab
  CHAR1-CHAR2     all characters from CHAR1 to CHAR2 in ascending order
  [CHAR*]         in SET2, copies of CHAR until length of SET1
  [CHAR*REPEAT]   REPEAT copies of CHAR, REPEAT octal if starting with 0
  [:alnum:]       all letters and digits
  [:alpha:]       all letters
  [:blank:]       all horizontal whitespace
  [:cntrl:]       all control characters
  [:digit:]       all digits
  [:graph:]       all printable characters, not including space
  [:lower:]       all lower case letters
  [:print:]       all printable characters, including space
  [:punct:]       all punctuation characters
  [:space:]       all horizontal or vertical whitespace
  [:upper:]       all upper case letters
  [:xdigit:]      all hexadecimal digits
  [=CHAR=]        all characters which are equivalent to CHAR

Translation occurs if -d is not given and both SET1 and SET2 appear.
-t may be used only when translating.  SET2 is extended to length of
SET1 by repeating its last character as necessary.  Excess characters
of SET2 are ignored.  Only [:lower:] and [:upper:] are guaranteed to
expand in ascending order; used in SET2 while translating, they may
only be used in pairs to specify case conversion.  -s uses the last
specified SET, and occurs after translation or deletion.

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/tr>
or available locally via: info '(coreutils) tr invocation'

💡 说明:帮助明确了三条行为约定,都是后文实测的依据——其一,SET2 比 SET1 短时用最后一个字符补齐,SET2 多余字符被忽略;其二,-s 作用于「最后指定的 SET」且发生在转换/删除之后;其三,[:lower:] 与 [:upper:] 只有成对用于转换时才有顺序保证。

2.3 版本确认

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

三、参数逐项实测

本章逐项实测每个参数与典型写法:每节先给命令与真实回显,再解释行为要点。

3.1 大小写转换:区间写法与字符类写法

最基本的转换:SET1 写小写字母区间 a-z,SET2 写大写字母区间 A-Z,按位置一一映射:

$ echo 'hello world' | tr 'a-z' 'A-Z'
HELLO WORLD

更推荐用字符类(POSIX class)写法,语义清晰且不依赖区间假设。大写转小写:

$ echo 'HELLO World 123' | tr '[:upper:]' '[:lower:]'
hello world 123

小写转大写:

$ echo 'Linux Text Processing' | tr '[:lower:]' '[:upper:]'
LINUX TEXT PROCESSING

💡 提示:[:upper:] 必须整体放在单引号里,漏掉方括号或引号会被 shell 展开出意想不到的文件名。字符类只有在转换(同时给 SET1 与 SET2)且成对使用 [:lower:]/[:upper:] 时行为才有保证,见 2.2 节帮助原文。

3.2 字符集区间与末位补齐

SET1 可以拼多个区间;SET2 比 SET1 短时按帮助约定用最后一个字符补齐:

$ echo 'abc 123' | tr 'a-z0-9' 'A-Z#'
ABC ###

SET1 是 26 个小写字母加 10 个数字共 36 个字符;SET2 是 26 个大写字母加 # 共 27 个字符,不足的 10 个位置全部用最后一个字符 # 补齐——所以所有数字都变成了 #。这条规则让「剩余字符统一映射为某字符」零成本实现。

区间+映射的另一个经典应用是 ROT13 混淆(字母表平移 13 位,再执行一次即还原):

$ echo 'hello' | tr 'a-zA-Z' 'n-za-mN-ZA-M'
uryyb

3.3 -d:删除字符

-d 删除 SET1 中的所有字符,此时不需要 SET2。删除数字:

$ echo 'abc123def456' | tr -d '0-9'
abcdef

删除指定符号:

$ echo 'a-b-c' | tr -d '-'
abc

删除换行符(把多行拼成一行)。因为输出不再有换行,紧跟一条 od 按字符回显字节,证明结果末尾连换行符都没有:

$ printf 'line1\nline2\nline3\n' | tr -d '\n'
line1line2line3
$ printf 'line1\nline2\nline3\n' | tr -d '\n' | od -An -c
   l   i   n   e   1   l   i   n   e   2   l   i   n   e   3

删除制表符:

$ printf 'a\tb\tc\n' | tr -d '\t'
abc

💡 提示:tr -d '\n' 是「合并多行为一行」的最快写法,但注意输出末尾没有换行符,直接拼接下一命令时记得补 \n 或用 echo 收尾。

3.4 -s:压缩连续重复字符

-s 把 SET 中字符的连续重复压成单个。压缩空格——清理多余空白的常用招:

$ echo 'hello   world' | tr -s ' '
hello world

压缩指定字符集合:

$ echo 'aaabbbccc' | tr -s 'abc'
abc

$ echo 'woooow!!!' | tr -s 'o!'
wow!

第二条里 o 与 ! 都在 SET 中,各自的连续重复分别被压缩,互不影响。

💡 提示:-s 作用于「最后指定的 SET」且发生在转换或删除之后(2.2 节帮助原文)——所以 tr -s 'x' 'y' 是先转换再压缩,理解这一点才能预测组合行为。

3.5 -c:取补集,及 -cs 组合

-c 对 SET1 取补集(除指定字符之外的所有字符)。删除「非数字」:

$ echo 'abc123abc' | tr -cd '0-9'
123

-cd 组合的语义是:把「0-9 的补集」(字母、空格、换行等)全部删掉,只留数字。注意输出 123 后连换行符也被删了(换行符属于补集)。

-cs 组合是提取单词清单的经典:把「字母数字的补集」压成换行,效果即「按非字母数字分词、每词一行」:

$ echo 'Hello, World! 123' | tr -cs 'a-zA-Z0-9' '\n'
Hello
World
123

💡 提示:-cs 'a-zA-Z0-9' '\n' 值得背下来——从任意文本中拉出单词/编号清单,比写 sed/awk 正则更直接。

3.6 只读标准输入:传文件参数会报错

tr 不接受文件参数,把文件名跟在 SET 后面会被当作多余操作数拒绝:

$ tr a-z A-Z /root/demo/tr/words.txt; echo exit=$?
tr: extra operand '/root/demo/tr/words.txt'
Try 'tr --help' for more information.
exit=1

正确姿势是用重定向或管道喂 stdin:

$ echo 'Linux Text Processing' | tr '[:lower:]' '[:upper:]'
LINUX TEXT PROCESSING

💡 提示:想直接处理文件用 tr SET1 SET2 < 文件;这一点与 cut、sort(都接受文件参数)不同,也与 rev(接受文件参数)不同,是 tr 最常被记错的地方。

3.7 不支持正则:字符一律按字面量处理

tr 的 SET 是字符集合,不是正则表达式。. 就是句点本身:

$ echo 'a.c 1+2' | tr '.' '_'
a_c 1+2

[a-z] 里的方括号也只是两个普通字符(真正起作用的是区间 a-z):

$ echo 'a[b]c' | tr '[a-z]' '[A-Z]'
A[B]C

第二条输出中 [、] 原样保留,证明方括号没有正则含义——小写转大写是区间 a-z 到 A-Z 的映射在起作用。需要正则能力的字符处理请用 sed 或 awk。

💡 技术拓展:字符/文本转换不止 tr 一家,常见工具横向对比——

工具能力层次适用场景
tr字符级映射、删除、压缩,无正则单字符维度批量转换(大小写、去数字、压空格,本文主角)
sed行级替换,支持正则与 \U/\L 大小写转换需要上下文匹配的替换、多字节中文
awk字段级处理,toupper()/tolower()按列转换、边转换边统计
iconv整文件编码转换GBK ↔ UTF-8 等编码迁移

本文以 tr 为主线实测其字符级能力;涉及正则与中文的转换见五、Q4,sed 用法见《sed 命令详解与参数实测(Ubuntu 22.04)》。

四、实战示例

前面各节覆盖了单个参数与组合行为,本节给三个可直接套用的场景。

1. 文本清洗成单词清单——标点与空格统一压成换行:

$ echo 'Hello, World! 123' | tr -cs 'a-zA-Z0-9' '\n'
Hello
World
123

2. 字段脱敏——删除字符串中的数字,只留可读部分:

$ echo 'abc123def456' | tr -d '0-9'
abcdef

3. ROT13 编解码——同一条命令再执行一次即可还原,适合轻量混淆:

$ echo 'hello' | tr 'a-zA-Z' 'n-za-mN-ZA-M'
uryyb

五、注意事项与常见问题

本节汇总 tr 使用中最容易踩坑的四个问题,均对应前文实测结论。

Q1:tr 能直接传文件名处理文件吗?

不能。tr 只读标准输入,传文件参数会报 extra operand 错误并退出码 1(3.6 节实测)。正确写法是 tr SET1 SET2 < 文件 或 cat 文件 | tr SET1 SET2。

Q2:tr 里的 .、[]、* 是正则吗?

不是。tr 完全没有正则,SET 是字符集合:. 就是句点、[ ] 就是方括号本身(3.7 节实测),[CHAR*REPEAT] 是 tr 自己的重复语法而非正则量词。需要正则的转换、删除、替换交给 sed。

Q3:SET1 与 SET2 长度不一致时会怎样?

两条规则(2.2 节帮助原文 + 3.2 节实测):SET2 短于 SET1 时,用 SET2 的最后一个字符循环补齐(数字全变 # 的实测);SET2 长于 SET1 时,多余字符被忽略。利用补齐规则可以一行实现「部分映射 + 其余统一映射」。

Q4:tr 能处理中文等多字节字符吗?

tr 的字符集按单字节语义设计,区间与补集都是字节级操作,对 UTF-8 中文这类多字节文本容易破坏编码,不建议使用。中文大小写转换可用 sed 的 \U/\L、awk 的 toupper()/tolower()(UTF-8 locale 下),编码转换交给 iconv。

六、参考链接