在 Linux 中对 tr 使用引号

Using quotes with tr in Linux

我在 Bash 脚本中遇到了一个奇怪的错误。该脚本将用户的输入更改为小写。如下:

# echo AcCCept | tr [:upper:] [:lower:]

我通过添加引号(或双引号)来解决。奇怪的是,在 system-a 上失败的完全相同的命令在 system-b 上运行良好。

system-a有Centos7.5.

system-b有Centos7.4.

然而,Bash 和 tr 版本在两者上完全相同。

有问题的系统-a 的输出:

[root@system-a ~]# echo AcCCept | tr [:upper:] [:lower:]
tr: misaligned [:upper:] and/or [:lower:] construct
[root@system-a ~]#
[root@system-a ~]#
[root@system-a ~]# echo AcCCept | tr [:upper:] [:lower:]
tr: misaligned [:upper:] and/or [:lower:] construct
[root@system-a ~]# echo AcCCept | tr "[:upper:]" "[:lower:]"
acccept
[root@system-a ~]# bash -version
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
<http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
[root@system-a ~]# tr --version
tr (GNU coreutils) 8.22
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Jim Meyering.
[root@system-a ~]# cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)
[root@system-a ~]#

系统 b 的输出 - 工作正常:

echo AcCCept | tr [:upper:] [:lower:]
acccept
[root@system-b ~]# echo AcCCept | tr "[:upper:]" "[:lower:]"
acccept
[root@system-b ~]# bash -version
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
[root@system-b ~]# tr --version
tr (GNU coreutils) 8.22
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Jim Meyering.
[root@system-b ~]# cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)
[root@system-b ~]#

同一个命令在system-a上失败而在system-b上运行正常的原因是什么?

未加引号时,[...]pathname expansion 约束。例如,如果您的目录中有一个名为 u 的文件,[:upper:] 将扩展到它:

$ ls                     # dir is empty
$ echo [:upper:]         # [:upper:] doesn't expand to anything and gets printed as is
[:upper:]
$ touch u                # filename 'u' created
$ echo [:upper:]         # [:upper:] expands to 'u'
u
$ echo '[:upper:]'       # [:upper:] is protected by quotes and doesn't get expanded 
[:upper:]

为什么这是个问题?引用自 man tr:

tr [OPTION]... SET1 [SET2]

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.

这意味着如果你在SET2中使用[:lower:][:upper:][:lower:]必须在SET1中使用。否则你会得到一个错误:

$ tr '[:upper:]' '[:lower:]' <<< "TeXt"      # SET1: [:upper:] SET2: [:lower:] => OK 
text
$ tr 'u' '[:lower:]' <<< "TeXt"              # SET2: [:lower:] SET1: not [:upper:] => ERROR      
tr: misaligned [:upper:] and/or [:lower:] construct 
$ tr '[:upper:]' 'l' <<< "TeXt"              # SET1: [:upper:] SET2: l => OK             
lelt