30

这里文档的定义在这里: http ://en.wikipedia.org/wiki/Here_document

如何在此处文档中键入选项卡?比如这样:

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

更新:

本题处理的问题:

  1. 扩展制表
  2. 虽然不扩大美元符号
  3. 在脚本等文件中嵌入here-doc
4

12 回答 12

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

cat > prices.txt << EOF
coffee${TAB}\$1.50
tea${TAB}\$1.50
burger${TAB}\$5.00
EOF
于 2010-09-17T09:07:18.733 回答
17

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

#!/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

请注意,<<-在这种情况下,我使用了 here doc 运算符。这使我可以缩进此处文档的行以提高可读性。缩进必须仅包含制表符(无空格)。

于 2010-09-17T02:11:01.437 回答
8

对我来说,我输入 ctrl-V 后跟 ctrl-I 以在 bash shell 中插入一个选项卡。这绕过了拦截选项卡的外壳,否则它具有“特殊”含义。Ctrl-V 后跟一个选项卡也应该可以工作。

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

使用您的示例文本,我最终在 price.txt 中获得了此内容:

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

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

cat > prices.txt <<"EOF"
于 2010-09-16T23:04:37.860 回答
5

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

您也可以暂时禁用 bash 制表符补全,例如,如果您想粘贴文本或者如果您想输入一个带有很多制表符的长 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 命令行上。

于 2014-03-20T06:23:10.567 回答
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.为防止变量扩展,请引用所有美元符号,或将 here 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.我不确定我是否理解这个子问题。此处文档的目的是将其嵌入到脚本中。前面的示例说明了如何在脚本或命令行中将此处的文档传递给 hexdump。

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

您还可以将此处文档的内容放入变量中,然后对其进行插值。

# 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,您还可能为每个回声花费一个外部进程)。

于 2011-08-04T09:26:19.573 回答
2

这是丹尼斯威廉姆森 答案的简短版本。灵感来自这里: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"
于 2013-05-10T10:45:55.853 回答
2

粘贴到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
于 2017-05-15T00:30:14.450 回答
1

回复:子问题#3,我将这个问题读为:

“[W] 如果我想 [...] 将注释的 here-doc 存储在与脚本相同的文件中以供以后参考,该怎么办?”

使用脚本名称作为 here doc 的输出,追加而不是替换,假设执行者也具有写入权限。在 here 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 编写一个将变量扩展为值的新脚本,执行它,然后您可以准确记录运行的内容,而不必跟踪代码。

于 2012-01-09T23:32:24.320 回答
1

如果要对文件缩进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

于 2021-05-21T10:10:47.137 回答
0

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

cat > prices.txt << EOF
$(echo $'coffee\t$1.50')
$(echo $'tea\t$1.50')
$(echo $'burger\t$5.00')
EOF
于 2014-05-07T19:04:04.377 回答
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 将 '\t' 转换为制表符。
  • 如果您在此处的文档中有类似的模式\\t,那么您将需要更复杂的 sed 调用,例如sed -e 's/\\t/\t/g' -e 's/\\\t/\\t/g'
于 2014-10-29T14:36:17.043 回答
-1

使用@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
于 2018-09-14T14:25:52.943 回答