代码之家  ›  专栏  ›  技术社区  ›  sixtyfootersdude

为什么SED不将\t识别为制表符?

  •  80
  • sixtyfootersdude  · 技术社区  · 14 年前
    sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
    

    我希望这个SED脚本在中的每一行的字体中插入一个制表符。 $filename 但事实并非如此。出于某种原因,它插入了一个t。奇怪…

    10 回复  |  直到 5 年前
        1
  •  102
  •   Mark Byers    14 年前

    不是所有版本的 sed 理解 \t . 只需插入文本选项卡(按 Ctrl键 - V 然后 标签 )

        2
  •  35
  •   sedit    14 年前

    使用bash,您可以像这样以编程方式插入制表符:

    TAB=$'\t' 
    echo 'line' | sed "s/.*/${TAB}&/g" 
    echo 'line' | sed 's/.*/'"${TAB}"'&/g'   # use of Bash string concatenation
    
        3
  •  18
  •   Bruno Bronosky    5 年前

    @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
    

    解释

    在狂欢中 $'string' 导致“ANSI-C膨胀”。当我们使用诸如 \t , \r , \n 等:来自: https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html#ANSI_002dC-Quoting

    表格中的文字 “串” 特别处理。这个词扩展了 到 一串 ,反斜杠转义字符替换为指定的 ANSI C标准。反斜杠转义序列(如果存在)是 解码…

    扩展的结果是单引号的,好像美元符号没有 出席了。

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

    我个人认为大多数避免bash的努力都是愚蠢的,因为避免bashims并不能*使代码可移植。(如果您将代码设置为 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无效。由开放小组在 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16 这就是为什么试图避免害羞通常会失败的一个例子。

        4
  •  7
  •   Thomas Bratt    11 年前

    我在Ubuntu12.04(LTS)上使用了类似这样的bash shell:

    附加新行 第二选项卡 什么时候 第一 匹配:

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

    替代 第一 具有 第二选项卡 :

    sed -i 's/first/\\t second/g' filename
    
        5
  •  3
  •   ByteHamster hexerei software    9 年前

    使用 $(echo '\t') . 您需要在模式周围加引号。

    例如,要删除制表符:

    sed "s/$(echo '\t')//"
    
        6
  •  2
  •   ghostdog74    14 年前

    你不需要使用 sed 要在实际情况下进行替换,只需在行的前面插入一个选项卡。与只打印出来相比,替换这种情况是一项昂贵的操作,尤其是在处理大文件时。因为它不是正则表达式,所以也更容易理解。

    使用AWK

    awk '{print "\t"$0}' $filename > temp && mv temp $filename
    
        7
  •  0
  •   Roman Nurik    14 年前

    sed 不支持 \t 也不是其他转义序列 \n 关于那件事。我找到的唯一方法是在脚本中使用 塞德 .

    也就是说,您可能需要考虑使用Perl或Python。下面是我编写的用于所有流regex’ing的一个简短的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
  •   Community rohancragg    7 年前

    我在Mac上用过这个:

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

    Used this link for reference

        9
  •  0
  •   Cees Timmerman    7 年前

    我使用的不是BSD SED,而是Perl:

    ct@MBA45:~$ python -c "print('\t\t\thi')" |perl -0777pe "s/\t/ /g"
       hi
    
        10
  •  0
  •   justincbagley    6 年前

    我认为其他人已经为其他方法充分阐明了这一点。( sed , AWK 等)。然而,我的 bash -具体答案(在Macos High Sierra和Centos 6/7上测试)如下。

    1)如果OP希望使用与最初提议类似的搜索和替换方法,那么我建议使用 perl 为此,如下所示。 笔记: regex的括号前的反斜杠不应该是必需的,并且此代码行反映了 $1 使用比 \1 具有 珀尔 替换运算符(例如 Perl 5 documentation )

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

    2)但是,正如 ghostdog74 ,因为所需的操作实际上是 添加选项卡 在将tmp文件更改为输入/目标文件之前的每行开头( $filename )我建议 珀尔 再次,但进行以下修改:

    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