tr使用范围的奇怪行为


10

我有一台使用tr时表现出奇怪行为的特定服务器。这是工作服务器上的示例:

-bash-3.2$ echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
1234567890
-bash-3.2$

这对我来说很有意义。

但是,这来自“特殊”服务器:

[root@host~]# echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
abcdefghijklmnpqrstuvwxyz1234567890

如您所见,删除所有小写字符失败。但是,它已删除字母“ o”

有趣的部分是以下两个示例,这些示例对我来说毫无意义:

[root@host~]# echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-n]
opqrstuvwxyz1234567890
[root@host~]# echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-o]
abcdefghijklmnpqrstuvwxyz1234567890
[root@host~]#

(同样,在上一个示例中删除了“ o”)

有人知道这里发生了什么吗?我无法在正在使用的任何其他Linux盒上进行复制。


5
切线相关:tr范围写入时不包含[...]。所以tr -d '[a-z]'会杀人a-z,还有人物[]。用于tr -d a-z仅杀死字母a-z
佐藤桂

Answers:


24

o在当前目录中有一个文件名为

foo> ls
foo> echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
1234567890
foo> touch o
foo> echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
abcdefghijklmnpqrstuvwxyz1234567890

[a-z]如果找到匹配项,shell将扩展字符串。

据称,这称为路径名扩展 man bash

扩展路径名
拆分单词后,除非已设置-f选项,否则bash会在每个单词中扫描字符* 、?和[。...(...)

bash将执行扩展。

[...]匹配其中任一字符。


@Chris您可以使用以下命令检查外壳的扩展情况echo:例如touch o ; echo tr -d [a-z]tr -d o
pabouk

8

怎么了

shell(bash)看到参数[a-z]。这是一个通配符模式(glob),它匹配任何小写字母¹。因此,外壳程序将查找与此模式匹配的文件名。有以下三种情况:

  • 当前目录中没有文件的名称是单个小写字母。然后,shell使通配符模式保持不变,并tr看到参数-d[a-z]。这就是大多数计算机上发生的情况。
  • 当前目录中的单个文件的名称为单个小写字母。然后,shell将模式扩展为该文件名,并tr查看参数-d和文件名。这是在服务器上发生的,并且会调用匹配文件,o因为我们可以看到tr已删除了letter o
  • 当前目录中的两个或多个文件的名称均为单个小写字母。然后,shell将模式扩展到匹配文件名的列表,并tr看到三个或更多参数:-d和文件名。由于tr期望在之后有一个参数-d,因此它将抱怨。

你应该做什么

如果命令的参数中包含特殊字符,则必须对其进行转义。将参数放在单引号中'…'(这是最简单的方法,还有其他方法)。在单引号内,除单引号本身外,所有字符都代表自己。如果参数中有单引号,则将其替换为'\''

tr -d '[a-z]'

但是请注意,这可能仍然不是您的意思!这告诉tr您删除小写字母和方括号。等价于tr -d ']a-z['tr '[]a-z'等。要删除小写字母,请使用

tr -d a-z

的参数tr是一个字符集。您可以在正则表达式或通配符模式中的字符集周围放置方括号,以表明它是字符集。但是一次tr只能处理一个字符。它的命令行参数是放在方括号内的内容

您确实需要用括号来指示字符类。在正则表达式中,可以在方括号内使用方括号来指示字符类,例如,[[:lower:]]*匹配任意数量的小写字母,[[:lower:]_]*匹配任意数量的小写字母和下划线。在的参数中tr,您需要不带方括号的集合,因此tr -d '[:lower:]'删除小写字母,tr -d '[:lower:]_'删除小写字母和下划线等。

¹ 在某些语言环境中可能与其他字符匹配


1
请注意,在Solaris 10(和其他基于SysV的较早版本的Unices)上,确实需要tr -d '[a-z]'使用/usr/bin/tr。使用/usr/xpg4/bin/trtr -d a-z可以但tr -d '[a-z]'不能删除[或删除]
斯特凡Chazelas

1
/usr/xpg4/bin/tr -d '[a-z]'没有删除,[也没有]在Solaris 11中得到明显修复。
StéphaneChazelas 18年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.