标签的简单sed更换神秘失败


43

这应该真的很简单,但是由于某些原因它不起作用:

sed -i.bak -E 's/\t/  /' file.txt

不是替换制表符,而是替换t字符。我已经尝试了所有可以想到的变体,使用引号等。我用Google搜索,发现其他所有人都使用非常相似的表达式,它们似乎很适合他们。

-E是OS X的东西。我以为失败可能是OS X的一些怪异的结果sed,所以我也使用Ruby进行了尝试(不带-i),并且得到了相同的结果:

ruby -pe '$_.gsub!(/\t/,"  ")' < file.txt > file.new

我在OS X和iTerm上使用的是Bash 3.2.51,尽管我看不到其中任何一个都非常相关。我没有设置任何奇怪的环境变量,尽管我可以发布您认为可能相关的任何变量。

有什么事吗

更新:我在尝试Ruby版本时肯定犯了其他错误或错字,因为Gilles指出它确实有效(而且我从来没有让他把我弄错!)。我不确定发生了什么,但是我很确定那一定是我的错误。


5
可能是你应该尝试更换\tsedwith语句CTRL-V<TAB>,其中<TAB>是tab键和CTRL-V是控制键和v压在一起。
unxnut 2014年

如果ruby也得到错误的答案,则可能是您的正则表达式库。(我已经测试了您的两个命令,并且都用2个空格替换了tab。)因此,如果希望您安装Gnu sed,那么它也将安装正确的库。
ctrl-alt-

Answers:


64

\tsed中的制表符字符的语法不是标准的。该转义是GNU sed扩展。在网上可以找到许多使用它的示例,因为很多人都使用GNU sed(这是非嵌入式Linux上的sed实现)。但是OS X sed和其他* BSD sed一样,不支持\ttab,而是视为\t反斜杠,后跟t

解决方案有很多,例如:

  • 使用文字制表符。

    sed -i.bak 's/  /  /' file.txt
    
  • 使用trprintf产生制表符。

    sed -i.bak "s/$(printf '\t')/  /" file.txt
    sed -i.bak "s/$(echo a | tr 'a' '\t')/  /" file.txt
    
  • 使用bash的字符串语法允许反斜杠转义

    sed -i.bak $'s/\t/  /' file.txt
    
  • 使用Perl,Python或Ruby。您发布的Ruby代码段可以正常工作。


对于脚本中包含的sed脚本...sed(通过-f选项使用),字面量制表符似乎是我唯一的选择。用vim编辑它时,这set noexpandtab一点很重要。
Tobias

警告:仅当您希望您的同事回到您的身后并稍后破坏脚本时,才使用“文字制表符”技术。仅tr当您希望您的同事在阅读脚本时让您面对您的脸时,才使用该技术。
布鲁诺·布鲁诺斯基

第二个双引号是否在第二个代码块中放错了位置?我不得不将其移动到当前结束单引号所在的位置。
艾伦·斯佩特斯

感谢您链接到bash字符串语法...我不知道(这是最好的选择,恕我直言)。
levigroker

sed $'s/<regex>/\t/' file.txt适用于插入,但是$当我尝试在替换中包含正则表达式的一部分时,似乎破坏了我的脚本,即sed $'s,\(ontology/[0-9]\+\),\t\txxx\1xxx\t\t,'以预期匹配值替换为xxxxxx。\1当使用bash的字符串语法时,是否有一个等效项?编辑:应该在xxx <U + 231C> xxx的中间出现U + 231C Unicode字符。
乔什

14

使用特定于Bash的引号,使您可以像在C中那样使用字符串,以便将真实的制表符传递给sed,而不是转义序列:

sed -i.bak -E $'s/\t/  /' file.txt

1
如果其他人想要查找有关它的更多信息,也称为“ ANSI-C”引用。
wisbucky

2
似乎可以在任何bourne shell上运行,也可以在非bash UNIX上运行。虽然不适用于csh-variant。
jornane '16

1

如前所述,并非所有sed实现都支持\t作为水平制表符的表示法。

您可以轻松实现替换:

 perl -pi.old -e 's{\t+}{ }g' file.txt

这将执行原位替换,将您的原始文件保留为“ * .old”。Perl允许经典的替代定界符,/使表达式更具可读性(即,没有“倾斜的牙签”综合症)。

+说一个制表符的一次或多次重复将被替换。该g修改使整个每一行的末尾全局替换。


1
sed -i $'s/\t/  /g' file.txt 

在OS X上对我有效,并且是我一直在linux上使用的同一命令。


请注意,这将替换每行上的所有选项卡,而OP仅打算替换第一行(从它们使用的命令来看)。
库沙兰丹

0

你也可以echo在里面使用sed

sed -i "s/$(echo '\t')//g"


请注意,这echo '\t'只会\t在某些shell的实现中输出echo
库萨兰达

0

如果要比OS X上的功能更强大sed(支持\t更多),请安装GNU sed


由于它也不能与Ruby一起使用,所以我不确定为什么我会得出OS X sed是问题的结论。您是否有理由相信这是问题所在?如果我有理由相信它可以解决问题,我很乐意安装GNU sed,但是似乎我已经排除了这一点。
iconoclast

使用Ruby,您只需使用一个反斜杠:ruby -pe '$_.gsub!(/\t/," ")' < file.txt
vinc17 2014年

0

如果可以使用bashzsh作为外壳可以,那么这是我能想到的最简单的解决方案:

sed "s/$(echo -n -e "\t")/ /" file.txt

但是请注意,echo标记(-n-e)在POSIX中是未定义的,因此POSIX兼容外壳不需要理解这些标记,但是出于兼容性的原因,许多标记都是如此。


-1

我很惊讶,没有人提出以下非常简单的解决方案:sed -i.bak -E 's/\\\t/ /' file.txt 应该可以解决问题 。

您需要对转义符进行转义(因此为3 \ s),以使sed理解在替换所有内容后您正试图在正则表达式中使用\ t字符...


为什么要特别使用三个反斜杠?
Michael Homer

3
如果我使用GNU sed,那么一个\ 就足够了,因为不需要转义。问题是BSD sed不支持选项卡的这种语法。
iconoclast

无法在我的El Capitan上使用。
富兰克林于

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.