如何在Bash脚本中将heredoc写入文件?

时间:2010-06-01 20:28:10

标签: bash heredoc

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

9 个答案:

答案 0 :(得分:908)

阅读Advanced Bash-Scripting Guide Chapter 19. Here Documents

这是一个将内容写入/tmp/yourfilehere

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

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

在shell脚本中,您可能希望使用缩进来使代码可读,但是这会使您在此文档中缩进文本产生不良影响。在这种情况下,使用<<-(后跟短划线)来禁用主要标签(注意,为了测试这一点,您需要用标签字符替换前导空格,因为我无法在此处打印实际的制表符。)

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

...或者使用sudo将heredoc写入文件:

cat <<'EOF' |  sed 's/a/b/' | sudo tee /etc/config_file.conf
foo
bar
baz
EOF

答案 1 :(得分:124)

不使用cat和I / O重定向,而是使用tee代替:

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

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

答案 2 :(得分:50)

注意:

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

  1. 是要覆盖现有文件,附加到现有文件还是写入新文件?
  2. 您的用户或其他用户(例如root)是否拥有该文件?
  3. 你想在字面上写下你的heredoc的内容,还是要在你的heredoc里面用bash解释变量引用?
  4. (还有其他维度/子问题我认为不重要。请考虑编辑此答案以添加它们!)以下是上面列出的问题维度的一些更重要的组合,以及各种不同的分隔标识符 - - EOF没有什么神圣之处,只要确保你用作分界标识符的字符串在你的heredoc中出现 not

    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
      

答案 3 :(得分:28)

在@Livven的answer上构建,这里有一些有用的组合。

  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
    

答案 4 :(得分:15)

需要root权限时

如果目标文件需要root权限,请使用|sudo tee代替>

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

答案 5 :(得分:11)

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

(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

答案 6 :(得分:2)

例如你可以使用它:

首先(进行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

Forth(使用变量):

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

答案 7 :(得分:0)

我喜欢在缩进的脚本中实现简洁,可读性和呈现的方法:

<<-End_of_file >file
→       foo bar
End_of_file

→       选项卡字符。

答案 8 :(得分:0)

如果您要使Heredoc缩进以提高可读性:

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

Bash中支持缩进的Heredoc的内置方法仅支持前导制表符,而不支持空格。

可以用awk替换Perl以节省一些字符,但是如果您了解基本的正则表达式,可能更容易记住Perl。