【问题标题】:tr command: strange behavior with | and \tr 命令:| 的奇怪行为和 \
【发布时间】:2018-05-07 20:30:10
【问题描述】:

假设我有一个包含内容的文件 test.txt:

+-foo.bar:2.4
|    bar.foo:1.1:test
\|  hello.goobye:3.3.3
   \|+- baz.yeah:4

我想使用 tr 命令删除以下字符集的所有实例:

{' ', '+', '-', '|', '\'}

对此进行了一些相当广泛的研究,但没有找到清晰/简洁的答案。 这是有效的命令:

输入:

cat test.txt | tr -d "[:blank:]|\\\+-"

输出:

foo.bar:2.4
bar.foo:1.1:test
hello.goobye:3.3.3
baz.yeah:4

我尝试了该集合的许多组合,发现“-”被视为范围指示符(如... [a-z]),因此必须放在末尾。但我有两个主要问题:

1) 为什么反斜杠必须双转义才能包含在集合中?

2) 为什么要放'|'在设置字符串的末尾导致 tr 程序删除文件中的所有内容,除了尾随的换行符?

【问题讨论】:

  • 至于 (2),能否请您显示您使用的具有该效果的确切字符串,并指定您当前语言环境的字符排序顺序(这决定了如何解释其中包含 - 的范围)? locale 命令发出的LC_COLLATE= 行的输出就可以了。
  • 顺便说一句,这是解释 Ivy 还是 Maven 输出?由于这些工具中的任何一个都可以将依赖关系解析结果转储为 XML,因此我通常会使用 XML 感知工具(XMLStarlet、xsltproc 等)来解释它们。

标签: bash escaping pipe translate tr


【解决方案1】:

像这样:

tr -d '\-|\\+[:blank:] ' < file

您必须转义 -,因为它用于表示字符范围,例如:

tr -d '1-5'

因此,如果您指的是文字连字符,则必须对其进行转义。你也可以把它放在最后。 (知道了,谢谢!:))

此外,当您指的是文字 \ 时,必须对 \ 进行转义,因为它具有转义序列所需的特殊含义。

其余字符不得转义。


为什么\ 在您的示例中必须双重转义?

这是因为您使用""(双引号)字符串来引用字符集。双引号字符串将由 shell 解释,双引号字符串中的 \\ 表示文字 \。试试:

echo "\+"
echo "\\+"
echo "\\\+"

为避免双重转义 \,您可以像上面的示例一样使用单引号。


为什么要放'|'在设置字符串的末尾导致 tr 程序删除文件中的所有内容,除了尾随的换行符?

CharlesDuffy's comment 后面加上| 也意味着你没有在最后加上未转义的-,这意味着它描述了一个字符范围,而实际范围取决于你的位置在集合中。

【讨论】:

  • 为了反斜杠的解释,可能还需要注意单引号和双引号之间的区别。 (比较echo "\\"echo '\\' 是一种简单的方法)。
  • POSIX(和 GNU)tr 不需要 [[:blank:]][:blank:] 就足够了(您的命令实际上会删除 [])。此外,- 作为组中的第一个或最后一个字符不必转义。
  • 如果您使用未转义的- 作为第一个字符,则必须使用-d --
  • @CharlesDuffy 我认为在回答之前阅读这个问题绝对是个好主意。 :) 对此我很抱歉。
  • 回复:|-at-the-end,根据定义,这意味着破折号在其他地方。因此,该破折号 的位置,以及在其当前语言环境的整理顺序中左侧事物和右侧事物之间的字符范围,因此与再现所描述的行为非常相关。
【解决方案2】:

另一种方法是定义允许的字符

$ tr -cd '[:alnum:]:.\n' <file

foo.bar:2.4
bar.foo:1.1:test
hello.goobye:3.3.3
baz.yeah:4

或者,也许删除所有前缀非单词字符

$ sed -E 's/\W+//' file

【讨论】:

猜你喜欢
  • 2015-03-28
  • 1970-01-01
  • 2012-04-05
  • 2012-06-21
  • 2022-01-05
  • 2015-12-07
  • 2015-01-11
  • 2012-10-22
  • 2019-01-18
相关资源
最近更新 更多