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

six*_*ude 94 regex bash sed

sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
Run Code Online (Sandbox Code Playgroud)

我期待这个sed脚本插入每行的字体中的选项卡,$filename但它不是.由于某种原因,它插入而不是..奇怪..

Mar*_*ers 116

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

  • 没错; 澄清:并非所有版本的sed都在表达式的替换部分理解`\ t`(它在模式匹配部分中识别出`\ t`就好了) (2认同)
  • awwwwwwwwwwwwwwwwwwwwww,好的,很有趣。真奇怪 为什么要让它在一处而不是另一处识别呢? (2认同)
  • 从脚本调用,这将无法工作:sh将忽略制表符.例如,shell脚本中的以下代码将添加$ TEXT_TO_ADD,而不是通过列表预先添加:sed"$ {LINE} a \\ $ TEXT_TO_ADD"$ FILE. (2认同)
  • @Dereckson和其他人 - 请参阅此答案:http://stackoverflow.com/a/2623007/48082 (2认同)
  • 德里克森s /能/不能/? (2认同)
  • 请仅在您绝对必须避免使用 bash 时才这样做!否则对文字选项卡进行编码是很糟糕的。即便如此,您也应该使用 `$(printf '\t')`,它(与 echo 不同)**是 POSIX 可移植的**。见 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16 (2认同)

小智 40

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

TAB=$'\t' 
echo 'line' | sed "s/.*/${TAB}&/g" 
echo 'line' | sed 's/.*/'"${TAB}"'&/g'   # use of Bash string concatenation
Run Code Online (Sandbox Code Playgroud)

  • 请记住,BASH 不会在单引号内扩展像 `$TAB` 这样的变量,因此您需要使用双引号。 (2认同)

Bru*_*sky 23

@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
Run Code Online (Sandbox Code Playgroud)

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

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

说明

在bash中$'string'导致"ANSI-C扩展".这也正是我们大多数人的预料,当我们使用之类的东西\t,\r,\n等来源:https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html#ANSI_002dC-Quoting

$'string'形式的单词是专门处理的.单词扩展为字符串,替换为ANSI C标准指定的反斜杠转义字符.反斜杠转义序列(如果存在)将被解码...

扩展结果是单引号,好像美元符号不存在一样.

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

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

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

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


Tho*_*att 8

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

要添加带选项卡的新行,请第一个匹配时添加第二行:

sed -i '/first/a \\t second' filename
Run Code Online (Sandbox Code Playgroud)

首先tab替换,第二个:

sed -i 's/first/\\t second/g' filename
Run Code Online (Sandbox Code Playgroud)

  • 双重转义是关键,即使用`\\ t`而不是`\ t`. (4认同)

rob*_*ord 5

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

例如。要删除选项卡:

sed "s/$(echo '\t')//"
Run Code Online (Sandbox Code Playgroud)

  • 有趣的是,您正在使用“GNU echo”特定功能(将 \t 解释为制表符)来解决“BSD sed”特定错误(将 \t 解释为 2 个单独的字符)。据推测,如果您有“GNU echo”,那么您也会有“GNU sed”。在这种情况下,您不需要使用 echo。使用 BSD echo `echo '\t'` 将输出 2 个单独的字符。POSIX 可移植方式是使用 `printf '\t'`。这就是为什么我说:不要试图通过不使用 bash 来使代码可移植。这比你想象的要难。使用“bash”是我们大多数人可以做的最便携的事情。 (6认同)