为什么sed没有将\ t识别为标签?

时间:2010-04-09 19:01:26

标签: regex bash sed

sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename

我希望这个sed脚本能够在$filename中的每一行的字体中插入一个标签,但事实并非如此。由于某种原因,它插入一个t而不是..奇怪..

12 个答案:

答案 0 :(得分:107)

并非sed的所有版本都理解\t。只需插入一个文字标签(按 Ctrl - V 然后标签)。

答案 1 :(得分:38)

使用Bash,您可以编程方式插入TAB字符,如下所示:

TAB=$'\t' 
echo 'line' | sed "s/.*/${TAB}&/g" 
echo 'line' | sed 's/.*/'"${TAB}"'&/g'   # use of Bash string concatenation

答案 2 :(得分:22)

@sedit是在正确的道路上,但定义一个变量有点尴尬。

解决方案(特定于bash)

在bash中执行此操作的方法是在单引号字符串前加上一个美元符号。

$ echo -e '1\n2\n3'
1
2
3

$ echo -e '1\n2\n3' | sed 's/.*/\t&/g'
t1
t2
t3

$ echo -e '1\n2\n3' | sed $'s/.*/\t&/g'
    1
    2
    3

如果您的字符串需要包含变量扩展,您可以将引用的字符串放在一起,如下所示:

$ timestamp=$(date +%s)
$ echo -e '1\n2\n3' | sed "s/.*/$timestamp"$'\t&/g'
1491237958  1
1491237958  2
1491237958  3

解释

在bash中$'string'导致" ANSI-C扩展"。这就是我们大多数人在使用\t\r\n等内容时所期望的内容。来自:https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html#ANSI_002dC-Quoting

  

$' string' 形式的单词将被特别处理。这个词扩大了   到 string ,替换为指定的反斜杠转义字符   ANSI C标准。反斜杠转义序列(如果存在)是   解码...

     

扩展结果是单引号,好像美元符号没有   在场。

解决方案(如果必须避免使用bash)

我个人认为大多数避免使用bash的努力都是愚蠢的,因为避免使用bashisms并不会使你的代码变得可移植。 (如果你把它变成bash -eu,你的代码会比你试图避免使用sh [除非你是一个绝对的POSIX忍者]而不那么脆弱。)但是不要有宗教争论那,我会给你最好的答案。

$ echo -e '1\n2\n3' | sed "s/.*/$(printf '\t')&/g"
    1
    2
    3

*最佳答案?是的,因为大多数反bash shell脚本编写者在代码中出错的一个例子是使用echo '\t' @robrecord's answer。这适用于GNU echo,但不适用于BSD echo。 The Open Group在http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16解释了这一点。这是为什么试图避免基本原则通常失败的原因。

答案 3 :(得分:8)

我在Ubuntu 12.04(LTS)上使用了类似的东西和Bash shell:

第一个匹配时,使用标签添加新行,第二个

sed -i '/first/a \\t second' filename

标签替换第一个,第二个

sed -i 's/first/\\t second/g' filename

答案 4 :(得分:3)

使用$(echo '\t')。你需要围绕模式引用。

EG。要删除标签:

sed "s/$(echo '\t')//"

答案 5 :(得分:2)

实际上,您不需要使用sed进行替换,只需在行前面插入一个标签即可。与仅打印出来相比,此案例的替换是一项昂贵的操作,尤其是在处理大文件时。它更容易阅读,因为它不是正则表达式。

例如使用awk

awk '{print "\t"$0}' $filename > temp && mv temp $filename

答案 6 :(得分:1)

我在Mac上使用过这个: -

sed -i '' $'$i\\\n\\\thello\n' filename

Used this link for reference

答案 7 :(得分:0)

sed不支持\t,也不支持\n之类的其他转义序列。我发现这样做的唯一方法是使用sed实际在脚本中插入制表符。

那就是说,你可能想考虑使用Perl或Python。这是我写的一个简短的Python脚本,我用于所有流正则表达式:

#!/usr/bin/env python
import sys
import re

def main(args):
  if len(args) < 2:
    print >> sys.stderr, 'Usage: <search-pattern> <replace-expr>'
    raise SystemExit

  p = re.compile(args[0], re.MULTILINE | re.DOTALL)
  s = sys.stdin.read()
  print p.sub(args[1], s),

if __name__ == '__main__':
  main(sys.argv[1:])

答案 8 :(得分:0)

而不是BSD sed,我使用perl:

ct@MBA45:~$ python -c "print('\t\t\thi')" |perl -0777pe "s/\t/ /g"
   hi

答案 9 :(得分:0)

我认为其他人已经为其他方法(sedAWK等)充分阐明了这一点。但是,接下来是我的bash特定答案(在macOS High Sierra和CentOS 6/7上测试)。

1)如果OP希望使用与其最初提出的搜索和替换方法类似的方法,那么我建议为此使用perl,如下所示。 注意事项:不需要在正则表达式的括号前加反斜杠,并且此代码行反映了$1\1perl替换运算符的使用效果更好(例如按照Perl 5 documentation)。

perl -pe 's/(.*)/\t$1/' $filename > $sedTmpFile && mv $sedTmpFile $filename

2)但是,正如ghostdog74所指出的那样,由于所需的操作实际上是在将tmp文件更改为输入/之前,在每行的开头简单地添加一个制表符目标文件($filename),我会再次推荐perl,但要进行以下修改:

perl -pe 's/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename
## OR
perl -pe $'s/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename

3)当然,tmp文件是多余的,因此最好“按原样”进行所有操作(添加-i标志并将其简化为更优雅的格式-

perl -i -pe $'s/^/\t/' $filename

答案 10 :(得分:0)

TAB=$(printf '\t')
sed "s/${TAB}//g" input_file

它对我在Red Hat上有效,它将从输入文件中删除选项卡。

答案 11 :(得分:0)

如果您知道某些字符没有被使用,您可以将“\t”翻译成别的东西。 cat my_file | tr "\t" "," | sed "s/(.*)/,\1/"