Linux Here文档(Here Document)是在Shell脚本内嵌入多行输入的标准方式,它以<<操作符加上定界符定义内容块,既可直接读写文件,也能将多段数据传递给命令,显著简化自动化运维脚本的编写。
linux here 文档是什么?一文读懂定义与用法
在编写Shell脚本时,经常需要向命令传递多行输入或生成包含多行内容的文件,Linux Here文档(又称Here Document)正是解决该需求的原始方法,它不需要单独创建文件或使用多条echo命令,只要在命令行或脚本中划定一个区块,区块内的所有行都会作为标准输入传递给对应命令。
标准语法与核心定界符
基本格式:
command << DELIMITER 此处是您需要传递的文本内容 可以包含多行 DELIMITER
关键规则:定界符(如EOF、END)必须成对出现,开头的<<后紧跟定界符,结尾的定界符必须单独成行且顶格写,社区共识中,最常用的定界符是EOF,但任何不包含特殊符号的字符串都可行,例如CONFIG_END、SQL_BLOCK。
定界符加引号后的行为差异
业内专家指出,给起始定界符加上单引号或双引号是控制变量展开和命令执行的核心技巧。
- 无引号:Shell会解析区块内的
$变量和`命令`,适合需要动态替换的场景。 - 单引号(
<< 'EOF'):所有内容视为字面字符串,不解析变量和反引号,适合保留模板原样。 - 双引号与单引号效果相同,但更推荐单引号以保证清晰。
示例对比:
# 工厂化场景:动态生成带变量的配置文件
cat << EOF > /etc/myapp.conf
server_name=${HOSTNAME}
port=8080
EOF
# 安全场景:生成含$符号的文本,不担心被替换
cat << 'EOF' > /tmp/example.txt
The cost is $100, no substitution here.
EOF
linux here 脚本场景:三个典型案例详解
Here文档的最大价值在于减少外部文件依赖、提升脚本可移植性,以下场景是社区公认的高频应用,每一个都可在现有生产环境中直接验证。
自动化配置文件生成
运维人员常需在部署脚本里生成Nginx、MySQL或自定义应用的配置,Here文档能将配置块直接嵌入脚本。
操作路径:
#!/bin/bash
cat > /etc/nginx/sites-available/default << 'NGINX_CONF'
server {
listen 80;
root /var/www/html;
index index.html;
}
NGINX_CONF
- 脚本执行后自动创建目标文件,无需额外复制。
- 定界符
NGINX_CONF加引号,避免符号干扰。 - 如需动态更改变量(如端口号),则不加引号并直接引用Shell变量。
多行消息输出与交互式输入
向用户展示完整帮助文档,或向工具传递多选项输入时,Here文档是最简洁的形式。
示例:批量创建用户(模拟交互输入)
sudo newusers << END user1:1000:1000:User One:/home/user1:/bin/bash user2:1001:1001:User Two:/home/user2:/bin/bash END
newusers命令从标准输入读取行,Here文档一行一个用户配置,无需手动创建临时文件。
数据库SQL脚本批量执行
在云服务器初始化脚本中,常用Here文档直接向数据库发送多条SQL语句。
mysql -u root -p$DB_PASS << 'SQL' CREATE DATABASE IF NOT EXISTS myapp; GRANT ALL ON myapp. TO 'appuser'@'localhost' IDENTIFIED BY 'secret'; FLUSH PRIVILEGES; SQL
- 定界符
SQL加引号,确保$DB_PASS变量提前由Shell替换,其他内容原样传递。 - 整个区块清晰表达了数据库操作的逻辑顺序。
linux here 命令与重定向对比:区别与适用场景
初学者常混淆Here文档和输入重定向(<)、Here字符串(<<<),三者在功能上相似,但适用场景和机制有明确分工。
Here文档 vs 输入重定向
| 特性 | Here文档 (<< DELIM) |
输入重定向 (< file) |
|---|---|---|
| 输入来源 | 脚本内部定义的多行内容 | 外部已存在的文件 |
| 可维护性 | 脚本自包含,无需附加文件 | 依赖相对路径,部署时需确保文件存在 |
| 变量扩展 | 支持开关(通过引号控制) | 无扩展,完全读取文件原内容 |
| 典型场景 | 临时生成配置、SQL脚本、帮助文本 | 读取已有日志、数据文件 |
选择建议较长且与脚本逻辑紧耦合时,用Here文档;当内容由其他工具管理或会被多脚本共用时,坚持使用外部文件配合输入重定向。
Here文档 vs Here字符串
Here字符串(<<<)仅用于向命令传递单行字符串,并附加一个换行符,两者适用边界清晰:
- 单行简短变量或文字 → Here字符串(
grep 'pattern' <<< "$var") - 多行数据块或自由格式 → Here文档(
cat << EOF ... EOF)
行业共识认为,Here文档在处理多行文本时是语法最清晰的选择,尤其适合脚本阅读者快速理解数据块的边界。
常见陷阱与专业技术要点
即使简单操作,也有让新手困惑的细节,以下四个问题在Stack Overflow的高票回答中反复出现。
定界符必须独立成行且无前导空白
错误的写法(定界符前有空格或TAB):
cat << EOF some text EOF # ← 这里多了一个空格,Shell不会识别为结束符
正确做法:结尾定界符必须顶格,前导的任何空格或TAB都会导致Shell继续读取直到在单独一行找到完全匹配的字符串。
定界符与内容重复导致意外终止
如果Here文档内的文本恰好包含与定界符完全相同的行(例如在文档中讨论EOF这个词),脚本会提前结束。防御策略:无关的独特定界符,如_EOF_、HEREDOC_END。
- 大型脚本中使用组合定界符,例如
MYBLOCK_001。
变量替换副作用:美元符号被意外解析
当脚本包含密码、私钥等含字符的文本时,必须使用单引号包围定界符,例:
ssh-keygen -t rsa -b 4096 -f /tmp/test -N '' << 'EOF' EOF
没有引号时,会被Shell当作变量前缀,可能导致预期外的替换或错误。
空行与缩进处理
默认情况下,Here文档保留所有空白字符,包括缩进和空行,如果希望消除脚本结构中的缩进,可以使用<<-(注意是减号)让Shell忽略前导TAB字符。
cat <<- END
this line is preceded by a tab
this line also
END
注意只对TAB生效,对空格无效,该特性在缩进风格严格的脚本中很常见,但不及普通定界符通用。
linux here 的常见问题解答
在嵌套脚本中使用linux here文档,如何避免定界符冲突?
选择层级编号式定界符,例如在外层脚本使用BLOCK1,内层使用BLOCK1_INNER,同时始终坚持在嵌套调用中对内层定界符加单引号,避免外层Shell变量错误替换内层内容。
linux here文档能否在一条命令中同时写入多个文件?
可以,借助tee命令将Here文档内容同时分发到多个目标:
tee file1 file2 file3 << EOF > /dev/null 这是同时写入三个文件的相同内容 EOF
tee的写入路径参数紧跟其后,> /dev/null抑制其在标准输出上的额外打印。
为什么我写的脚本在部分Linux发行版上执行失败,但本机正常?
大概率是默认Shell不同所致,Here文档是Bourne Shell(sh)和Bash共有的特性,但某些嵌入式系统或最小化安装环境默认使用Dash作为/bin/sh,Dash对Here文档的解析严格,尤其对<<-的支持不如Bash完整,解决方法是在脚本第一行指定解释器:#!/bin/bash或#!/bin/dash,并测试定界符是否顶格,确保脚本头清晰,避免依赖不可移植的扩展语法。
Linux Here文档并不是新鲜概念,但它仍是在脚本中嵌入原始数据最直接、可审计性最强的工具,熟练掌握定界符的选择、引号对变量展开的影响以及嵌套场景的排除技巧,能帮助你在自动化部署、初始化配置等任务中编写出更健壮且易于维护的Shell脚本。
首发原创文章,作者:世雄 - 原生数据库架构专家,如若转载,请注明出处:https://idctop.com/article/498806.html


