How can I write a heredoc to a file in Bash script?
如何将here文档写入bash脚本中的文件?
阅读高级bash脚本指南第19章。这里有文件。
下面是一个将内容写入
1 2 3 4 | cat << EOF > /tmp/yourfilehere These contents will be written to the file. This line is indented. EOF |
注意,最后的"eof"(
在shell脚本中,您可能希望使用缩进使代码可读,但是这可能会产生不希望的效果,即在此处文档中缩进文本。在这种情况下,使用
1 2 3 4 5 6 7 | #!/usr/bin/env bash if true ; then cat <<- EOF > /tmp/yourfilehere The leading tab is ignored. EOF fi |
如果不想解释文本中的变量,请使用单引号:
1 2 3 | cat << 'EOF' > /tmp/yourfilehere The variable $FOO will not be interpreted. EOF |
要通过命令管道传送HereDoc,请执行以下操作:
1 2 3 4 5 | cat <<'EOF' | sed 's/a/b/' foo bar baz EOF |
输出:
1 2 3 | foo bbr bbz |
…或者使用
1 2 3 4 5 | cat <<'EOF' | sed 's/a/b/' | sudo tee /etc/config_file.conf foo bar baz EOF |
不使用
1 2 3 4 5 | tee newfile <<EOF line 1 line 2 line 3 EOF |
它更简洁,而且不像重定向操作符,如果需要写入具有根权限的文件,它可以与
注:
- 以下是这条线索中其他答案的浓缩和整理,特别是斯特凡·拉西夫斯基和谢尔盖·斯特罗本特的优秀作品。
- lasiewski和我在高级bash脚本指南中推荐ch 19(这里是文档)。
问题(如何在bash脚本中将here文档(又称heredoc)写入文件?)具有(至少)3个主要独立维度或子问题:
(还有其他我认为不重要的维度/子问题。考虑编辑此答案以添加它们!)下面是上面列出的问题维度的一些更重要的组合,带有各种不同的分隔标识符——
要覆盖您拥有的现有文件(或写入新文件),请替换HereDoc中的变量引用:
1 2 3 4 | 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 |
要附加您拥有的现有文件(或写入新文件),请替换HereDoc中的变量引用:
1 2 3 4 | 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 |
要使用HereDoc的文字内容覆盖您拥有的现有文件(或写入新文件):
1 2 3 4 | 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 |
要附加您拥有的现有文件(或写入新文件),请使用HereDoc的文字内容:
1 2 3 4 | 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 |
要覆盖根目录拥有的现有文件(或写入新文件),请替换HereDoc中的变量引用:
1 2 3 4 | 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 |
要附加一个用户=foo拥有的现有文件(或写入新文件),以及heredoc的文本内容:
1 2 3 4 | 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 |
基于@livven的答案,这里有一些有用的组合。
变量替换,保留前导制表符,覆盖文件,回显到stdout
1 2 3 | tee /path/to/file <<EOF ${variable} EOF |
无变量替换,保留前导制表符,覆盖文件,回显到stdout
1 2 3 | tee /path/to/file <<'EOF' ${variable} EOF |
变量替换,删除前导制表符,覆盖文件,回显到stdout
1 2 3 | tee /path/to/file <<-EOF ${variable} EOF |
变量替换,保留前导制表符,追加到文件,回显到stdout
1 2 3 | tee -a /path/to/file <<EOF ${variable} EOF |
变量替换,保留前导制表符,覆盖文件,不回显到stdout
1 2 3 | tee /path/to/file <<EOF >/dev/null ${variable} EOF |
以上也可与
1 2 3 | sudo -u USER tee /path/to/file <<EOF ${variable} EOF |
当需要根权限时
当目标文件需要根权限时,使用
1 2 3 | cat << 'EOF' |sudo tee /tmp/yourprotectedfilehere The variable $FOO will *not* be interpreted. EOF |
对于可能有此问题的未来人员,请使用以下格式:
1 2 3 4 5 6 7 8 9 10 | (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 |
例如,您可以使用它:
首先(进行ssh连接):
1 2 3 4 5 6 7 8 9 | 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 |
第二个(执行命令):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
第三(执行命令):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 |
四(使用变量):
1 2 3 4 5 6 7 8 9 10 11 12 | 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 2 3 | <<-End_of_file >file → foo bar End_of_file |
其中,