如何在bash here-document中键入选项卡?

时间:2010-09-16 23:02:06

标签: bash tabs heredoc

here-document的定义如下: http://en.wikipedia.org/wiki/Here_document

如何在here-document中键入选项卡?比如这个:

cat > prices.txt << EOF
coffee\t$1.50
tea\t$1.50
burger\t$5.00
EOF

更新:

这个问题涉及的问题:

  1. 展开标签字符
  2. 虽然没有扩展美元符号
  3. 将here-doc嵌入文件,例如脚本

12 个答案:

答案 0 :(得分:19)

TAB="$(printf '\t')"

cat > prices.txt << EOF
coffee${TAB}\$1.50
tea${TAB}\$1.50
burger${TAB}\$5.00
EOF

答案 1 :(得分:15)

您可以在脚本中嵌入此文档,并将其分配给变量,而不使用单独的文件:

#!/bin/bash
read -r -d '' var<<"EOF"
coffee\t$1.50
tea\t$1.50
burger\t$5.00
EOF

然后printfecho -e会将\t个字符展开到标签中。您可以将其输出到文件:

printf "%s\n" "$var" > prices.txt

或者使用printf -v将变量的值赋给自身:

printf -v var "%s\n" "$var"

现在var或文件prices.txt包含实际标签而不是\t

您可以在读取此文档时将其处理,而不是将其存储在变量中或将其写入文件中:

while read -r item price
do
    printf "The price of %s is %s.\n" $item $price    # as a sentence
    printf "%s\t%s\n" $item $price                  # as a tab-delimited line
done <<- "EOF"
    coffee $1.50    # I'm using spaces between fields in this case
    tea $1.50
    burger $5.00
    EOF

请注意,在这种情况下,我使用<<-作为此处的doc运算符。这允许我缩进这里doc的行以便于阅读。缩进必须仅包含制表符(无空格)。

答案 2 :(得分:8)

对我来说,我输入ctrl-V后跟ctrl-I在bash shell中插入一个标签。这绕过了拦截制表符的shell,否则它具有“特殊”含义。 Ctrl-V后跟一个标签也应该有用。

在here文档中嵌入美元符号时,需要禁用shell变量的插值,或者在每个变量前面添加反斜杠以进行转义(即\$)。

使用您的示例文本,我在price.txt中找到了这个内容:

coffee\t.50
tea\t.50
burger\t.00

因为未设置$1$5。可以通过引用终结符来关闭插值,例如:

cat > prices.txt <<"EOF"

答案 3 :(得分:5)

正如其他人所说,您可以在键入时键入CTRL-V然后选项卡以插入单个选项卡。

您也可以暂时禁用bash tab-completion,例如,如果您想要粘贴文本,或者如果要输入带有大量标签的long here-doc:

bind '\C-i:self-insert'     # disable tab-completion

# paste some text or type your here-doc
# note you don't use "\t" you just press tab

bind '\C-i:complete'        # reenable tab-completion

编辑:如果您使用的是Mac并使用iTerm 2,则现在有一个“带文字标签的粘贴”选项,允许使用标签将代码粘贴到bash命令行上。

答案 4 :(得分:2)

我注意到已经给出了正确的答案,但我试图总结一个更简洁的答案。

1。没有什么可以阻止您在此处的文档中使用文字制表符。

要在Bash提示符下键入文字选项卡,您需要将其转义。转义字符是ctrl-V(除非你有自定义绑定来覆盖它)。

$ echo -n 't<ctrl-v><tab>ab' | hexdump -C
00000000  74 09 61 62                                       |t.ab|
00000004

在大多数程序员的编辑器中,插入文字制表符应该是微不足道的(虽然有些编辑可能也想要转义。在Emacs中,ctrl-Q TAB插入一个文字制表符。)

为了易读,最好使用某种转义而不是文字制表符。在Bash中,$'...'字符串语法很方便。

2。为防止变量扩展,请引用所有美元符号,或将此处的doc终止符放在引号中。

$ hexdump -C <<HERE
> t<ctrl-v><tab>\$ab
HERE
00000000  74 09 24 61 62 0a                                 |t.$ab.|
00000006

$ hexdump -C <<'HERE'
> t<ctrl-v><tab>$ab
HERE
00000000  74 09 24 61 62 0a                                 |t.$ab.|
00000006

在这种情况下,使用单引号或双引号无关紧要。

3。我不确定我理解这个问题。这里的文档的目的是将其嵌入脚本中。前面的示例说明了如何在脚本或命令行中将here文档传递给hexdump。

如果您想多次使用相同的此处文档,则没有直接的方法可以直接执行此操作。该脚本可以将此文档写入临时文件,然后将该临时文件传递给多个命令,然后擦除临时文件。 (如果脚本被中断,请注意使用trap删除临时文件。)

您还可以将here文档的内容放在变量中,然后插入它。

# Note embedded newlines inside the single quotes,
# and the use of $'...\t...' to encode tabs
data=$'coffee\t$1.50
tea\t$1.50
burger\t$5.00'

# Run Word Count on the data using a here document
wc <<HERE
$data
HERE

# Count number of tab characters using another here document with the same data
grep -c $'\t' <<HERE
$data
HERE

你可以等效地使用echo -E "$data" | wc; echo -E "$data" | grep -c $'\t'但是使用echo不是很优雅而且可能性较差(尽管如果你的目标是bash,所有的回声应该是相同的。如果你的目标一般是Bourne shell,你可能会也为每个回声花费一个外部过程。)

答案 5 :(得分:2)

以下是Dennis Williamson's answer的缩短版本。来自这里的灵感:http://tldp.org/LDP/abs/html/here-docs.html

#!/bin/bash

var=$(echo -e "$(cat <<"EOF"
coffee\t$1.50
tea\t$1.50
burger\t$5.00
EOF
)")

echo "$var"

答案 6 :(得分:1)

Re:子问题#3,我把这个问题读成:

  

“如果我想[...]存储here-doc评论相同的话   file作为脚本供以后参考?“

使用脚本名称作为此文档的输出,附加而不是替换,假设执行程序也具有写入权限。在此处的doc块中不会解释Shell注释。

_thisline=${LINENO}
cat <<EOF >>$0
#====== $(date) =========
#On this run, these variable values were used as of line ${_thisline}: A=${A}, B=${B}, B=${C}

EOF

以类似的方式,您可以使用here doc编写一个新的脚本,将变量扩展为值,执行它,然后您就可以准确记录运行的内容而不必跟踪代码。

答案 7 :(得分:1)

粘贴到heredoc中的标签消失,因为bash仍然将它们解释为标记自动完成序列/请求开始的特殊字符。

如果要在当前shell中快速粘贴heredoc,可以通过在当前shell的生命周期内禁用自动完成来执行此操作。

如果您粘贴包含标签的heredoc,那么正常自动完成会发生什么:

$ cat <<EOF
TABAFTERTABBEFORE
TABAFTERTABBEFORE
TABAFTERTABBEFORE
TABAFTERTABBEFORE
TABAFTERTABBEFORE
EOF
TABAFTERTABBEFORE
TABAFTERTABBEFORE
TABAFTERTABBEFORE
TABAFTERTABBEFORE
TABAFTERTABBEFORE

运行此命令:

bind "set disable-completion on"

再次粘贴并保留标签:

$ cat <<EOF
> TABAFTER      TABBEFORE
> TABAFTER      TABBEFORE
> TABAFTER      TABBEFORE
> TABAFTER      TABBEFORE
> TABAFTER      TABBEFORE
> EOF
TABAFTER    TABBEFORE
TABAFTER    TABBEFORE
TABAFTER    TABBEFORE
TABAFTER    TABBEFORE
TABAFTER    TABBEFORE

答案 8 :(得分:0)

原始问题的一个简单直接的解决方案是使用 $(echo $'...')成语:

cat > prices.txt << EOF
$(echo $'coffee\t$1.50')
$(echo $'tea\t$1.50')
$(echo $'burger\t$5.00')
EOF

答案 9 :(得分:0)

如果您使用像sed这样的工具并引用分隔符(EOF),事情会变得更简单:

sed 's/\\t/\t/g' > prices.txt << 'EOF'
coffee\t$1.50
tea\t$1.50
burger\t$5.00
EOF
  • 引用EOF可防止参数(美元符号)扩展。
  • sed convert&#39; \ t&#39;进入制表符。
  • 如果你在这里的文档中有\\t这样的模式,那么你需要一个更复杂的sed调用,例如:sed -e 's/\\t/\t/g' -e 's/\\\t/\\t/g'

答案 10 :(得分:0)

使用@EOF,它将保留标签。

cat >> /etc/logrotate.d/nginx <<@EOF
/var/log/nginx/*log { 
    daily
    rotate 10
    missingok
    notifempty
    compress
    sharedscripts
    postrotate
        /bin/kill -USR1 $(cat /var/run/nginx.pid 2>/dev/null) 2>/dev/null || :
    endscript
}
@EOF

答案 11 :(得分:0)

如果您想对文件缩进使用制表符为heredoc: 您只需要将缩进的制表符与带有空格的文档制表符分开:

try_me() {
    # @LinuxGuru's snippet; thanks!
    sed 's/^ //g' >> tmp.conf <<-EOF
     /var/log/nginx/*log { 
        daily
        rotate 10
        missingok
        notifempty
        compress
        sharedscripts
        postrotate
            /bin/kill -USR1 $(cat /var/run/nginx.pid 2>/dev/null) 2>/dev/null || :
        endscript
     }
    EOF
}

try_me

唯一的缺点是不缩进的行看起来有点奇怪;他们在脚本上有一个领先的空白字符

  • /var/log/nginx/*log
  • }

但是,在生成的文件中不会出现这种情况(sed 's/^ //g' 而不是 cat