884

如何将此处的文档写入 Bash 脚本中的文件?

4

10 回答 10

1310

阅读高级 Bash 脚本指南第 19 章。这里是 Documents

这是一个将内容写入文件的示例/tmp/yourfilehere

cat << EOF > /tmp/yourfilehere
These contents will be written to the file.
        This line is indented.
EOF

请注意,最后的 'EOF' (The LimitString) 在单词前面不应有任何空格,因为这意味着LimitString不会被识别。

在 shell 脚本中,您可能希望使用缩进来使代码可读,但这可能会产生缩进 here 文档中的文本的不良影响。在这种情况下,使用<<-(后跟破折号)禁用前导制表符(请注意,要对此进行测试,您需要用制表符替换前导空格,因为我无法在此处打印实际的制表符。)

#!/usr/bin/env bash

if true ; then
    cat <<- EOF > /tmp/yourfilehere
    The leading tab is ignored.
    EOF
fi

如果您不想解释文本中的变量,请使用单引号:

cat << 'EOF' > /tmp/yourfilehere
The variable $FOO will not be interpreted.
EOF

通过命令管道传输heredoc:

cat <<'EOF' |  sed 's/a/b/'
foo
bar
baz
EOF

输出:

foo
bbr
bbz

...或使用以下命令将heredoc写入文件sudo

cat <<'EOF' |  sed 's/a/b/' | sudo tee /etc/config_file.conf
foo
bar
baz
EOF
于 2010-06-02T03:40:50.250 回答
185

与其使用cat和 I/O 重定向,不如使用它可能有用tee

tee newfile <<EOF
line 1
line 2
line 3
EOF

sudo它更简洁,而且与重定向运算符不同,如果您需要写入具有 root 权限的文件,它可以结合使用。

于 2013-06-13T17:35:13.950 回答
71

笔记:

问题(如何将 here 文档(又名heredoc)写入 bash 脚本中的文件?)(至少)有 3 个主要的独立维度或子问题:

  1. 您要覆盖现有文件、追加到现有文件还是写入新文件?
  2. 您的用户或其他用户(例如root)是否拥有该文件?
  3. 你想直接写你的heredoc的内容,还是让bash解释你的heredoc中的变量引用?

(还有其他我认为不重要的维度/子问题。考虑编辑此答案以添加它们!)以下是上面列出的问题维度的一些更重要的组合,以及各种不同的定界标识符——没有什么神圣的 about EOF,只需确保您用作定界标识符的字符串不会出现在您的 heredoc 中:

  1. 要覆盖您拥有的现有文件(或写入新文件),请替换 heredoc 中的变量引用:

    cat << EOF > /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, with the variable contents substituted.
    EOF
    
  2. 要附加您拥有的现有文件(或写入新文件),请替换 heredoc 中的变量引用:

    cat << FOE >> /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, with the variable contents substituted.
    FOE
    
  3. 要使用 heredoc 的文字内容覆盖您拥有的现有文件(或写入新文件):

    cat << 'END_OF_FILE' > /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, without the variable contents substituted.
    END_OF_FILE
    
  4. 要使用 heredoc 的文字内容附加您拥有的现有文件(或写入新文件):

    cat << 'eof' >> /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, without the variable contents substituted.
    eof
    
  5. 要覆盖 root 拥有的现有文件(或写入新文件),请替换 heredoc 中的变量引用:

    cat << until_it_ends | sudo tee /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, with the variable contents substituted.
    until_it_ends
    
  6. 使用 heredoc 的文字内容附加 user=foo 拥有的现有文件(或写入新文件):

    cat << 'Screw_you_Foo' | sudo -u foo tee -a /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, without the variable contents substituted.
    Screw_you_Foo
    
于 2014-09-18T03:11:56.583 回答
58

为了以@Livven 的回答为基础,这里有一些有用的组合。

  1. 变量替换,保留前导选项卡,覆盖文件,回显到标准输出

    tee /path/to/file <<EOF
    ${variable}
    EOF
    
  2. 没有变量替换,保留前导选项卡,覆盖文件,回显到标准输出

    tee /path/to/file <<'EOF'
    ${variable}
    EOF
    
  3. 变量替换,删除前导选项卡,覆盖文件,回显到标准输出

    tee /path/to/file <<-EOF
        ${variable}
    EOF
    
  4. 变量替换,保留前导选项卡,附加到文件,回显到标准输出

    tee -a /path/to/file <<EOF
    ${variable}
    EOF
    
  5. 变量替换,保留前导选项卡,覆盖文件,不回显到标准输出

    tee /path/to/file <<EOF >/dev/null
    ${variable}
    EOF
    
  6. sudo以上也可以结合

    sudo -u USER tee /path/to/file <<EOF
    ${variable}
    EOF
    
于 2016-08-02T21:48:11.657 回答
19

当需要 root 权限时

当目标文件需要 root 权限时,使用|sudo tee代替>

cat << 'EOF' |sudo tee /tmp/yourprotectedfilehere
The variable $FOO will *not* be interpreted.
EOF

cat << "EOF" |sudo tee /tmp/yourprotectedfilehere
The variable $FOO *will* be interpreted.
EOF
于 2014-02-13T20:55:02.370 回答
14

对于未来可能遇到此问题的人,以下格式有效:

(cat <<- _EOF_
        LogFile /var/log/clamd.log
        LogTime yes
        DatabaseDirectory /var/lib/clamav
        LocalSocket /tmp/clamd.socket
        TCPAddr 127.0.0.1
        SelfCheck 1020
        ScanPDF yes
        _EOF_
) > /etc/clamd.conf
于 2010-06-01T21:02:53.413 回答
3

例如,您可以使用它:

首先(建立ssh连接):

while read pass port user ip files directs; do
    sshpass -p$pass scp -o 'StrictHostKeyChecking no' -P $port $files $user@$ip:$directs
done <<____HERE
    PASS    PORT    USER    IP    FILES    DIRECTS
      .      .       .       .      .         .
      .      .       .       .      .         .
      .      .       .       .      .         .
    PASS    PORT    USER    IP    FILES    DIRECTS
____HERE

第二(执行命令):

while read pass port user ip; do
    sshpass -p$pass ssh -p $port $user@$ip <<ENDSSH1
    COMMAND 1
    .
    .
    .
    COMMAND n
ENDSSH1
done <<____HERE
    PASS    PORT    USER    IP
      .      .       .       .
      .      .       .       .
      .      .       .       .
    PASS    PORT    USER    IP    
____HERE

第三(执行命令):

Script=$'
#Your commands
'

while read pass port user ip; do
    sshpass -p$pass ssh -o 'StrictHostKeyChecking no' -p $port $user@$ip "$Script"

done <<___HERE
PASS    PORT    USER    IP
  .      .       .       .
  .      .       .       .
  .      .       .       .
PASS    PORT    USER    IP  
___HERE

第四(使用变量):

while read pass port user ip fileoutput; do
    sshpass -p$pass ssh -o 'StrictHostKeyChecking no' -p $port $user@$ip fileinput=$fileinput 'bash -s'<<ENDSSH1
    #Your command > $fileinput
    #Your command > $fileinput
ENDSSH1
done <<____HERE
    PASS    PORT    USER    IP      FILE-OUTPUT
      .      .       .       .          .
      .      .       .       .          .
      .      .       .       .          .
    PASS    PORT    USER    IP      FILE-OUTPUT
____HERE
于 2014-02-16T10:17:06.170 回答
2

For those looking for a pure bash solution (or a need for speed), here's a simple solution without cat:

# here-doc tab indented
{ read -r -d '' || printf >file '%s' "$REPLY"; } <<-EOF
        foo bar
EOF

or for an easy "mycat" function (and avoid leaving REPLY in environment):

mycat() {
  local REPLY
  read -r -d '' || printf '%s' "$REPLY"
}
mycat >file <<-EOF
        foo bar
EOF

Quick speed comparison of "mycat" vs OS cat (1000 loops >/dev/null on my OSX laptop):

mycat:
real    0m1.507s
user    0m0.108s
sys     0m0.488s

OS cat:
real    0m4.082s
user    0m0.716s
sys     0m1.808s

NOTE: mycat doesn't handle file arguments, it just handles the problem "write a heredoc to a file"

于 2021-11-02T19:19:25.333 回答
0
于 2018-11-15T19:01:54.623 回答
0

If you want to keep the heredoc indented for readability:

$ perl -pe 's/^\s*//' << EOF
     line 1
     line 2
EOF

The built-in method for supporting indented heredoc in Bash only supports leading tabs, not spaces.

Perl can be replaced with awk to save a few characters, but the Perl one is probably easier to remember if you know basic regular expressions.

于 2020-09-09T02:29:37.050 回答