tr 'nt+'命令在外壳 bash 中不起作用?


Text1  Text2
(3 tabs)  text 3
(4 tabs)  text 4
 (2 tabs) text 5
Text2 Text7
(2 tabs) Text8  

我有一个上述格式的文本文件。基本上我想做的是,我想用一个特殊字符替换连续的换行符和制表符。我正在使用这个命令

tr 'nt+' '@'

我期待这个输出

Text1 Text2@text 3@text 4@text 5<br/>
Text2 Text7@Text8

这个正则表达式可以很好地与eclipse查找和替换(也可以与editplus)一起工作。然而,tr将所有内容放在一行中。

谁能告诉我tr有什么问题,用这个正则表达式?分辨率是多少?

tr命令使用错误。它允许您将一个字符(类)转换为另一个字符(类),但您不能将其用于像这样的正则表达式字符串替换。

您可以使用gnu sed代替:

sed ':a;N;$!ba;s/nt+/@/g;' file
Text1  Text2@text 3@text 4@text 5
Text2 Text7@text8

这个sed命令有两个部分:

  1. :a;N;$!ba;:通过N命令将当前行和下一行附加到模式空间(是一个循环,在应用字符串替换之前先读取整个输入)
  2. s/nt+/@/g;@
  3. 替换后跟一个或多个制表符的换行符

EDIT:这是一个非gnu sed版本,也可以在OSX上工作:

sed -e ':a' -e 'N' -e '$!ba' -e $'s/\ntt*/@/g' file

@anubhava的有用答案解释了为什么tr在这里不起作用,但是纯粹的sed解决方案有一个轻微的缺点(除了有点难以理解之外):它在执行所需的字符串替换之前将整个输入文件读入内存(这对于较小的文件来说可能完全没问题)。

如果你:

  • 有GNU awkmawk
  • 和不介意合并awksed

这里有一个解决方案,它不会一次读取整个输入:

awk -v RS='nt+' -v ORS=@  '1' file | sed '$d'
  • -v RS='nt+'将[input]记录分隔符分配给RS,该分隔符将输入(可能跨行)分隔为基于至少一个空格的换行符分隔的记录。请注意,使用正则表达式作为记录分隔符是不符合posix的,因此需要GNU awkmawk
  • -v ORS=@@赋值给变量ORS(输出记录分隔符)。
  • 1在这种情况下构成了整个awk程序:它是一个与{print}有效相同的常见快捷方式,即它只是输出每个输入记录,后面跟着输出记录分隔符ORS。然而,由于每一个记录,包括最后一个记录,都以ORS结束,我们最终在输出的末尾得到n@,这是不希望的。
  • sed '$d'简单地从输出中删除最后一行($匹配最后一行,d删除它)。

最新更新