tr 使用范围的奇怪行为

tr 使用范围的奇怪行为

我有一台特定的服务器在使用 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 机器上重现。

答案1

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 将执行扩展。

[...] 匹配任何一个包含的字符。

答案2

怎么了

shell (bash) 看到参数[a-z]。这是一个通配符模式(a全局),它匹配任何小写字母。因此,shell 会查找与此模式匹配的文件名。分三种情况:

  • 当前目录中没有文件的名称是单个小写字母。然后 shell 保持通配符模式不变,并tr查看参数-d[a-z]。大多数机器上都会发生这种情况。
  • 当前目录中的单个文件的名称为单个小写字母。然后 shell 将模式扩展为该文件名,并tr查看参数-d和文件名。这发生在服务器上,并且调用匹配的文件,o因为我们可以看到tr删除了字母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:]_'删除小写字母和下划线等。

^ 在某些区域设置中它可能与其他字符匹配

相关内容