为什么命令 tr "\'\\\"\?\!" "01234" 不起作用?

为什么命令 tr "\'\\\"\?\!" "01234" 不起作用?

在终端中,如果我定义一些变量 char 如下:

export char=\'\\\"\?\!

实际上,char 是字符串

'\"?!

然后我使用tr命令替换'\"?!为数字01234

tr "\'\\\"\?\!" "01234"

我以为我会得到

01234

相反,我得到了

0\123

如果有人能向我解释发生了什么,我将非常感激。

似乎用sed命令单独替换每个字符可以避免这个问题,但为什么呢?

答案1

不仅仅是shell,tr它本身也将反斜杠解释为特殊的转义字符,详细信息请参阅其手册。因此,当您想要替换反斜杠时,需要确保tr接收文字(两个反斜杠)。\\这可以通过例如在 shell 中完成char=...\\\\...,这部分不需要进一步解释,因为您正确理解了 shell 如何处理反斜杠。

这可能对您来说不方便,但在许多其他情况下很方便,并且允许字符集或 NUL 字节成为搜索或替换集的一部分(否则这是不可能的)。例如,要将 NUL 分隔的字符串转换为换行符分隔的字符串,您可以执行类似的操作tr '\0' '\n' < /proc/1234/environ,或者使用小写字符串tr '[:upper:]' '[:lower:]'。如果tr没有转义字符,这些都是不可能的。

答案2

始终将字符串和脚本括在单引号 ( ') 中,除非您需要使用双引号 ( ") 让 shell 解释它。看https://mywiki.wooledge.org/Quotes。通过使用双引号,您将邀请 shell 进入,因此将自己带入“转义”地狱,您必须转义字符串中的字符,以便 shell 首先用完,然后再次转义它们以供工具使用,因此您需要添加多个转义层而不是 1 层。只是不要这样做,而是使用单引号:

$ printf '%s\n' ''\''\"?!'
'\"?!

$ printf '%s\n' ''\''\"?!' | tr ''\''\\"?!' '01234'
01234

定义变量时也是如此char。而不是使用所有这些反斜杠:

export char=\'\\\"\?\!

只需正确单引号字符串即可:

$ export char=''\''\"?!'

$ printf '%s\n' "$char"
'\"?!

$ printf '%s\n' "$char" | tr ''\''\\"?!' '01234'
01234

在上面的内容中,您需要知道的是,要在 shell 中获取 a'内的- 封闭的字符串是,您需要对 中的反斜杠进行转义,以便知道将其视为文字反斜杠而不是后续 的转义。''\''trtr"

相关内容