tr'\ n \ t +'命令无法在shell bash中运行?

时间:2014-07-02 14:35:41

标签: regex bash shell

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

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

tr '\n\t+' '@'

我期待这个输出

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

这个正则表达式可以正常使用eclipse查找和替换(也可以使用editplus)。但是tr将所有内容放在一行中。

任何人都可以通过此正则表达式告诉我tr的问题是什么?而且,决议是什么?

2 个答案:

答案 0 :(得分:3)

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

您可以改为使用gnu sed

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

此sed命令有两部分:

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

    编辑:以下是适用于OSX的非gnu sed 版本:

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

答案 1 :(得分:1)

@anubhava's helpful answer解释了为什么tr在这里不起作用,但纯sed解决方案有一点点缺点(除了有点难以理解):它在执行所需的字符串替换之前,将整个输入文件读入内存(对于较小的文件,这可能非常好)。

如果您:

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

这是一个解决方案,无法一次性读取整个输入

awk -v RS='\n\t+' -v ORS=@  '1' file | sed '$d'
  • -v RS='\n\t+'分配给RS,即[输入]记录分隔符,它根据分隔换行后跟至少1个空格将输入(可能跨行)分成记录。请注意,它使用正则表达式作为不符合POSIX的记录分隔符,因此需要GNU awkmawk
  • -v ORS=@@分配给变量ORS,即输出记录分隔符。
  • 在这种情况下,
  • 1构成了整个awk程序:它是一个与{print}实际上相同的常用快捷方式,即它只输出每个输入记录,然后是{ {1}},输出记录分隔符。
  • 但是,由于每个记录(包括 last 记录)都以ORS终止,因此我们最终会在ORS结束时输出,这是不受欢迎的。
  • \n@只是从输出中删除最后一行(sed '$d'与最后一行匹配,$删除它。)