如何在Bash脚本中为文件编写一个文档?

时间:2021-12-30 13:56:48

How can I write a here document to a file in Bash script?

如何在Bash脚本中为文件写入一个文档?

7 个解决方案

#1


705  

Read the Advanced Bash-Scripting Guide Chapter 19. Here Documents.

阅读高级的bash脚本指南第19章。这里的文档。

Here's an example which will write the contents to a file at /tmp/yourfilehere

这里有一个示例,它将把内容写入/tmp/yourfilehere文件。

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

Note that the final 'EOF' (The LimitString) should not have any whitespace in front of the word, because it means that the LimitString will not be recognized.

注意,最后的“EOF”(限制字符串)在单词前面不应该有任何空格,因为它意味着不能识别限制字符串。

In a shell script, you may want to use indentation to make the code readable, however this can have the undesirable effect of indenting the text within your here document. In this case, use <<- (followed by a dash) to disable leading tabs (Note that to test this you will need to replace the leading whitespace with a tab character, since I cannot print actual tab characters here.)

在shell脚本中,您可能想要使用缩进来使代码可读,但是这可能会在您的本文档中对文本进行缩进。在本例中,使用<<-(后跟一个破折号)禁用引导标签(注意,为了测试这个,您需要用一个制表符替换主要的空白,因为我不能在这里打印实际的制表符。)

#!/usr/bin/env bash

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

If you don't want to interpret variables in the text, then use single quotes:

如果您不想在文本中解释变量,那么使用单引号:

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

To pipe the heredoc through a command pipeline:

通过一条命令管道来管道:

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

Output:

输出:

foo
bbr
bbz

... or to write the the heredoc to a file using sudo:

…或者使用sudo将该文档写到文件中:

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

#2


99  

Instead of using cat and I/O redirection it might be useful to use tee instead:

而不是使用cat和I/O重定向,使用tee可能会有用:

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

It's more concise, plus unlike the redirect operator it can be combined with sudo if you need to write to files with root permissions.

它更简洁,而且与重定向操作符不同,如果需要使用根权限写入文件,它可以与sudo结合使用。

#3


36  

Note:

注意:

The question (how to write a here document (aka heredoc) to a file in a bash script?) has (at least) 3 main independent dimensions or subquestions:

这个问题(如何在bash脚本中编写一个文件(又名以下文档)到一个文件中?)(至少)有3个主要的独立维度或子问题:

  1. Do you want to overwrite an existing file, append to an existing file, or write to a new file?
  2. 您想要覆盖现有的文件,附加到现有的文件,还是写入新文件?
  3. Does your user or another user (e.g., root) own the file?
  4. 您的用户或其他用户(例如,root)拥有该文件吗?
  5. Do you want to write the contents of your heredoc literally, or to have bash interpret variable references inside your heredoc?
  6. 您想要从字面上写您的文档的内容,还是要在您的文档中使用bash解释变量引用?

(There are other dimensions/subquestions which I don't consider important. Consider editing this answer to add them!) Here are some of the more important combinations of the dimensions of the question listed above, with various different delimiting identifiers--there's nothing sacred about EOF, just make sure that the string you use as your delimiting identifier does not occur inside your heredoc:

(还有一些我认为不重要的维度/子问题。考虑编辑这个答案来添加它们!)下面是上面列出的问题的一些更重要的组合,有各种不同的分隔标识符——EOF没有什么神圣之处,只是要确保您使用的字符串作为分隔符不会出现在您的文档中:

  1. To overwrite an existing file (or write to a new file) that you own, substituting variable references inside the 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. To append an existing file (or write to a new file) that you own, substituting variable references inside the 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. To overwrite an existing file (or write to a new file) that you own, with the literal contents of the 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. To append an existing file (or write to a new file) that you own, with the literal contents of the 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. To overwrite an existing file (or write to a new file) owned by root, substituting variable references inside the 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. To append an existing file (or write to a new file) owned by user=foo, with the literal contents of the heredoc:

    将已存在的文件(或写入一个新文件)附加到用户=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
    

#4


12  

When root permissions are required

When root permissions are required for the destination file, use |sudo tee instead of >:

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

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

#5


12  

To build on @Livven's answer, here are some useful combinations.

在@Livven的答案上,这里有一些有用的组合。

  1. variable substitution, leading tab retained, overwrite file, echo to stdout

    变量替换,引导标签保留,覆盖文件,echo到stdout。

    tee /path/to/file <<EOF
    ${variable}
    EOF
    
  2. no variable substitution, leading tab retained, overwrite file, echo to stdout

    没有变量替换,引导标签保留,覆盖文件,echo到stdout。

    tee /path/to/file <<'EOF'
    ${variable}
    EOF
    
  3. variable substitution, leading tab removed, overwrite file, echo to stdout

    变量替换,引导标签删除,覆盖文件,echo到stdout。

    tee /path/to/file <<-EOF
        ${variable}
    EOF
    
  4. variable substitution, leading tab retained, append to file, echo to stdout

    变量替换,引导标签保留,附加到文件,echo到stdout。

    tee -a /path/to/file <<EOF
    ${variable}
    EOF
    
  5. variable substitution, leading tab retained, overwrite file, no echo to stdout

    变量替换,引导标签保留,覆盖文件,没有echo到stdout。

    tee /path/to/file <<EOF >/dev/null
    ${variable}
    EOF
    
  6. the above can be combined with sudo as well

    以上可以与sudo结合使用。

    sudo -u USER tee /path/to/file <<EOF
    ${variable}
    EOF
    

#6


10  

For future people who may have this issue the following format worked:

对于未来可能会有以下问题的人来说:

(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

#7


2  

As instance you could use it:

例如,您可以使用它:

First(making ssh connection):

第一个(使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

Second(executing commands):

第二个(执行命令):

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

Third(executing commands):

第三(执行命令):

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(using variables):

(使用变量)。

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

#1


705  

Read the Advanced Bash-Scripting Guide Chapter 19. Here Documents.

阅读高级的bash脚本指南第19章。这里的文档。

Here's an example which will write the contents to a file at /tmp/yourfilehere

这里有一个示例,它将把内容写入/tmp/yourfilehere文件。

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

Note that the final 'EOF' (The LimitString) should not have any whitespace in front of the word, because it means that the LimitString will not be recognized.

注意,最后的“EOF”(限制字符串)在单词前面不应该有任何空格,因为它意味着不能识别限制字符串。

In a shell script, you may want to use indentation to make the code readable, however this can have the undesirable effect of indenting the text within your here document. In this case, use <<- (followed by a dash) to disable leading tabs (Note that to test this you will need to replace the leading whitespace with a tab character, since I cannot print actual tab characters here.)

在shell脚本中,您可能想要使用缩进来使代码可读,但是这可能会在您的本文档中对文本进行缩进。在本例中,使用<<-(后跟一个破折号)禁用引导标签(注意,为了测试这个,您需要用一个制表符替换主要的空白,因为我不能在这里打印实际的制表符。)

#!/usr/bin/env bash

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

If you don't want to interpret variables in the text, then use single quotes:

如果您不想在文本中解释变量,那么使用单引号:

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

To pipe the heredoc through a command pipeline:

通过一条命令管道来管道:

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

Output:

输出:

foo
bbr
bbz

... or to write the the heredoc to a file using sudo:

…或者使用sudo将该文档写到文件中:

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

#2


99  

Instead of using cat and I/O redirection it might be useful to use tee instead:

而不是使用cat和I/O重定向,使用tee可能会有用:

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

It's more concise, plus unlike the redirect operator it can be combined with sudo if you need to write to files with root permissions.

它更简洁,而且与重定向操作符不同,如果需要使用根权限写入文件,它可以与sudo结合使用。

#3


36  

Note:

注意:

The question (how to write a here document (aka heredoc) to a file in a bash script?) has (at least) 3 main independent dimensions or subquestions:

这个问题(如何在bash脚本中编写一个文件(又名以下文档)到一个文件中?)(至少)有3个主要的独立维度或子问题:

  1. Do you want to overwrite an existing file, append to an existing file, or write to a new file?
  2. 您想要覆盖现有的文件,附加到现有的文件,还是写入新文件?
  3. Does your user or another user (e.g., root) own the file?
  4. 您的用户或其他用户(例如,root)拥有该文件吗?
  5. Do you want to write the contents of your heredoc literally, or to have bash interpret variable references inside your heredoc?
  6. 您想要从字面上写您的文档的内容,还是要在您的文档中使用bash解释变量引用?

(There are other dimensions/subquestions which I don't consider important. Consider editing this answer to add them!) Here are some of the more important combinations of the dimensions of the question listed above, with various different delimiting identifiers--there's nothing sacred about EOF, just make sure that the string you use as your delimiting identifier does not occur inside your heredoc:

(还有一些我认为不重要的维度/子问题。考虑编辑这个答案来添加它们!)下面是上面列出的问题的一些更重要的组合,有各种不同的分隔标识符——EOF没有什么神圣之处,只是要确保您使用的字符串作为分隔符不会出现在您的文档中:

  1. To overwrite an existing file (or write to a new file) that you own, substituting variable references inside the 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. To append an existing file (or write to a new file) that you own, substituting variable references inside the 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. To overwrite an existing file (or write to a new file) that you own, with the literal contents of the 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. To append an existing file (or write to a new file) that you own, with the literal contents of the 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. To overwrite an existing file (or write to a new file) owned by root, substituting variable references inside the 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. To append an existing file (or write to a new file) owned by user=foo, with the literal contents of the heredoc:

    将已存在的文件(或写入一个新文件)附加到用户=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
    

#4


12  

When root permissions are required

When root permissions are required for the destination file, use |sudo tee instead of >:

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

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

#5


12  

To build on @Livven's answer, here are some useful combinations.

在@Livven的答案上,这里有一些有用的组合。

  1. variable substitution, leading tab retained, overwrite file, echo to stdout

    变量替换,引导标签保留,覆盖文件,echo到stdout。

    tee /path/to/file <<EOF
    ${variable}
    EOF
    
  2. no variable substitution, leading tab retained, overwrite file, echo to stdout

    没有变量替换,引导标签保留,覆盖文件,echo到stdout。

    tee /path/to/file <<'EOF'
    ${variable}
    EOF
    
  3. variable substitution, leading tab removed, overwrite file, echo to stdout

    变量替换,引导标签删除,覆盖文件,echo到stdout。

    tee /path/to/file <<-EOF
        ${variable}
    EOF
    
  4. variable substitution, leading tab retained, append to file, echo to stdout

    变量替换,引导标签保留,附加到文件,echo到stdout。

    tee -a /path/to/file <<EOF
    ${variable}
    EOF
    
  5. variable substitution, leading tab retained, overwrite file, no echo to stdout

    变量替换,引导标签保留,覆盖文件,没有echo到stdout。

    tee /path/to/file <<EOF >/dev/null
    ${variable}
    EOF
    
  6. the above can be combined with sudo as well

    以上可以与sudo结合使用。

    sudo -u USER tee /path/to/file <<EOF
    ${variable}
    EOF
    

#6


10  

For future people who may have this issue the following format worked:

对于未来可能会有以下问题的人来说:

(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

#7


2  

As instance you could use it:

例如,您可以使用它:

First(making ssh connection):

第一个(使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

Second(executing commands):

第二个(执行命令):

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

Third(executing commands):

第三(执行命令):

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(using variables):

(使用变量)。

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