「tr(1)」-

替换、压缩、删除字符

命令语法格式

tr [OPTION]… SET1 [SET2]

命令描述

命令tr将来自标准输入的数据写入到标准输出,执行以下操作之一:

  • 替换,以及可选地缩减结果中的重复字符,
  • 缩减重复字符,
  • 删除字符,
  • 删除字符,然后从结果中缩减重复的字符。

参数SET1和SET2(如果给出)参数定义了一个有序的字符集。下面分别称为SET1和SET2,统称时我们使用setX。这些setX是tr进行操作的输入字符。–complement(-c,-C)选项将SET1替换为其“补充”(“补充”是指所有不在SET1中的字符)。

目前tr完全支持单字节字符。最终它将支持多字节字符;当它支持的时候,-C选项会使它补充字符集,而-c会使它补充一组值。只有当某些值不是字符时,这种区别才有意义,并且只有在输入包含编码错误时,使用多字节编码的区域设置中才有可能。

命令支持的选项及含义

-c, -C, –complement
使用SET1的补集,即处理SET1中以外的字符。

-d, –delete
删除SET1中的字符,而不是默认的翻译。

-s, –squeeze-repeats
删除输入中出现在最后一个SET中的重复字符,并将其替换为单个字符。简单说,把重复字符压缩为一个字符。

-t, –truncate-SET1
先将SET1截断,使其长度等于SET2。

–help
显示帮助信息并退出。

–version
显示版本信息并退出。

字符集:指定字符集

参数SET1和SET2的格式类似于正则表达式的格式;但是,它们不是正则表达式,只是字符列表。在这些字符串中,大多数字符只是表示自己,没有特殊含义。但字符串可以包含下面列出的缩写,这些组合序列是有特殊含义的。其中一些只能在SET1或SET2中使用,如下所述:

反斜线转义

可以识别以下反斜杠转义序列:

‘\a’
Control-G.

‘\b’
Control-H.

‘\f’
Control-L.

‘\n’
Control-J.

‘\r’
Control-M.

‘\t’
Control-I.

‘\v’
Control-K.

‘\ooo’
序列中的ooo给出的值代表了一个8位(1字节)的字符,为1到3个八进制数字。请注意,’\400’被解释为两字节的字符序列’\040’与’0’。

‘\\’
反斜线。

上面是支持的所有的转义序列。

范围

符号’m-n’按升序解释为从m到n的所有字符。例如,’0-9’与’0123456789’相同。m应该在n之前;如果不是,则会产生错误。

在GNU的tr中,不支持使用方括号括起的范围语法(System V的语法)。以这种格式指定的翻译操作有时会按预期工作,因为括号通常是代表自身。但是,应该避免使用它们,因为它们有时会出现意外情况。例如,tr -d ‘[0-9]’会删除括号和数字。

许多历史上常见且甚至被接受的范围用途都不具有可移植性。例如,在使用’A-Z’范围时,在EBCDIC主机上’A’到’Z’不是连续的,但它们在ASCII中是连续的。如果你可以依赖于兼容POSIX的tr版本,那么解决这个问题的最好方法就是使用字符类(见下文)。否则,枚举范围内的所有成员是最便携的(也是最难看的)。

重复的字符

参数SET2中使用符号‘[c*n]’表示n个字符’c‘。因此,’[y*6]‘与’yyyyyy‘相同。SET2中的使用符号‘[c*]’表示与SET1中字符个数相同的’c‘。如果’n‘以’0’开头,则以八进制解释,否则以十进制解释。

字符类

符号'[:class:]’会被解释为在类class中预定义的所有字符。除了upper和lower之外,字符不按特定顺序进行解释,它们按升序进行解释。当给出–delete(-d)和–squeeze-repeats(-s)选项时,可以在SET2中使用任何字符类。否则,在SET2中只使用lower和upper字符类,并且仅在SET1中的相同相对位置上指定了相应的字符类(分别为大写和小写)时才接受。这样做指定了大小写转换。给出无效的类名时,会出现错误。可用的class名称如下:

alnum
字母和数字。

alpha
字母。

blank
水平空白。

cntrl
控制字符。

digit
数字。

graph
可打印字符,但是不包含空格。

lower
小写字母。

print
可打印字符,包括空格。

punct
标点符号。

space
水平或者垂直空白。

upper
大写字母。

xdigit
十六进制数字。

上面是所有的字符类。

等价的类

语法'[=c=]’解释与c等效的所有字符,没有特定的顺序。等价类是一种相对较新的发明,旨在支持非英语字母表。但似乎没有标准的方法来定义它们或确定它们的内容。因此,在GNU tr中它们没有被完全实现;每个字符的等价类仅由该字符组成,没有特别的用途。

翻译:将一组字符更改为另一组字符

当给出SET1和SET2并且未给出–delete(-d)选项时,tr执行转换。命令tr将其标准输入中出现在SET1的每个字符转换为SET2中的相应位置的字符。标准输入中不在SET1中的字符将保持不变。当一个字符在SET1中出现多次,并且对应SET2中不相同的字符时,只使用最后一个字符。例如,这两个命令是等效的:

# tr aaa xyz

# tr a z

命令tr的常见用法是将小写字符转换为大写。这可以通过多种方式完成。以下是其中三种:

# tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ

# tr a-z A-Z

# tr ‘[:lower:]’ ‘[:upper:]’

但请注意,使用上述类似a-z等形式的范围是不可移植的。

当tr执行转换时,参数SET1和SET2通常具有相同的长度。如果SET1比SET2短,则忽略SET2末尾的额外字符,使其与SET1长度相同。

另一方面,使SET1长于SET2是不可移植的;POSIX说结果是未定义的。在这种情况下,BSD的tr根据需要通过重复SET2的最后一个字符,以此来将SET2设置为与SET1相同的长度。System V的tr将SET1截断为SET2的长度。

默认情况下,GNU的tr会处理这种情况,类似于BSD的tr。当给出–truncate-SET1(-t)选项时,GNU的tr会像System V的tr一样处理这种情况。对于除转换之外的操作,将忽略此选项。

在这种情况下,像System V的tr这样的行为会打破相对常见的BSD语言习惯:

# tr -cs A-Za-z0-9 ‘\012’

因为它只将零字节(NUL,参数SET1的补码中的第一个元素)而不是所有非字母数字转换为换行符。

顺便说一句,上面的习惯用法是不可移植的,因为它使用了范围,并假设换行的八进制代码是012,且假设符合POSIX标准的tr命令。这里有一个更好的方式:

# tr -cs ‘[:alnum:]’ ‘[\n*]’

压缩和删除:删除字符

(1)仅给出–delete(-d)选项时,命令tr将删除输入中出现在SET1中的所有字符。

(2)当仅给出–squeeze-repeats(-s)选项,而不进行翻译时,命令tr将输入中那些在SET1中出现的重复序列进行替换,并且该字符只出现一次。

(3)当同时给出–delete和–squeeze-repeats时,命令tr首先使用SET1执行任何删除,然后使用SET2从任何剩余的字符中处理重复。

(4)在翻译时,也可以使用–squeeze-repeats选项,在这种情况下,命令tr首先执行翻译,然后使用SET2从任何剩余的字符中处理重复。

以下是一些示例,用于说明各种选项组合:

针对(1)。删除所有零字节:

# tr -d ‘\0’

针对(4)。将所有单词单独放在行上。这会将所有非字母数字的字符转换为换行符(LF),然后将每个重复换行符串压缩为一个换行符:

# tr -cs ‘[:alnum:]’ ‘[\n*]’

针对(2)。将重复换行符的每个序列转换为单个换行符。即,删除空白行:

# tr -s ‘\n’

在文档中查找双倍出现的单词。例如,人们经常会写出由换行符分隔的“the the”。下面的Shell脚本,首先将标点符号和空白字符的每个序列转换为单个换行符。这使得每个“单词”本身就成了单独一行。接下来,它将所有大写字符映射到小写,最后它使用-d选项运行uniq,仅打印出重复的单词:

#!/bin/sh
cat -- "$@" \
  | tr -s '[:punct:][:blank:]' '[\n*]' \
  | tr '[:upper:]' '[:lower:]' \
  | uniq -d

上面这个脚本只是找出重复的单词,不是对其进行去重。

删除一小组字符通常很简单。例如,要删除所有’a’,’x’,’M’,你会这样做:

# tr -d axM

但是,当’-‘是其中要被删除的字符之一时,它可能很棘手,因为’-‘具有特殊含义。我们要执行的任务与上面的相同,但同时也删除所有’-‘字符,我们可能会尝试tr -d -axM,但这会失败,因为tr会尝试将-a解释为命令行选项。或者,我们可以尝试将‘-’放在字符串中间,tr -d a-xM,但这不会起作用,因为它会将a-x解释为一个范围(字符’a’…’x’的范围)。解决问题的一种方法是将连字符放在字符列表的末尾:

# tr -d axM-

或者你可以使用’–‘来终止选项的处理:

# tr -d — -axM

更一般地,使用带有’-‘的字符类符号[=c=]:

# tr -d ‘[=-=]axM’

请注意,在上面的示例中,我们使用了单引号来保护方括号([])不被Shell的解释。

退出状态

退出状态为零表示成功,非零值表示失败。

相关手册

查看在线手册:http://www.gnu.org/software/coreutils/tr

查看info手册:info ‘(coreutils) tr invocation’

参考文献

  • man 1 tr, version GNU coreutils 8.28

更新日志

  • 10/27/2017 创建文章
  • 06/28/2018 修改文章内容