| 核心结论 | 说明 |
|---|---|
| EOF 不是固定关键字 | 它只是 here document 的结束标记,可以换成任意字符串 |
<<EOF 会把多行文本作为标准输入 | 常与 cat、ssh、mysql、tee 配合使用 |
<<-EOF 只会去掉 Tab,不会去掉空格 | 结束标记前如果是空格,仍然无法识别 |
<<'EOF' 会关闭变量替换 | 适合生成包含 $VAR、反引号、命令替换的原样文本 |
1.简介
Here Document 是 Shell 中用于书写多行输入的一种语法。
常见写法:
| |
EOF 是 End Of File 的缩写,但在这里不是固定关键字,只是人为约定的结束标记。可以换成 ABC、END、SQL、CONFIG 等任意字符串。
2.说明
2.1 基本语法
语法:
| |
执行时,Shell 会把 MARKER 中间的内容作为 command 的标准输入。
示例:
| |
输出:
| |
等价理解:cat 本来从标准输入读取内容,here document 临时提供了一段标准输入。
2.2 EOF 可以自定义
EOF 只是结束标记,不是语法关键字。
| |
也可以用更有语义的标记:
| |
建议:
| 场景 | 推荐标记 |
|---|---|
| 普通文本 | EOF |
| SQL | SQL |
| YAML 配置 | YAML |
| Nginx 配置 | NGINX |
| JSON | JSON |
2.3 写入文件:覆盖与追加
覆盖写入:
| |
追加写入:
| |
也可以把重定向写在后面:
| |
两种写法效果一样,但更推荐把重定向写在命令后面第一种形式,便于一眼看出目标文件。
2.4 变量替换与原样输出
默认情况下,here document 内容会进行变量替换、命令替换。
| |
输出类似:
| |
如果希望原样输出,不展开变量和命令,需要给结束标记加引号。
| |
输出:
| |
生成脚本、YAML、systemd unit、Nginx 配置时,如果内容中包含
$变量,优先使用 <<'EOF',避免被当前 Shell 提前展开。2.5 <<EOF 与 <<-EOF
两者区别:
| 写法 | 行首缩进处理 | 说明 |
|---|---|---|
<<EOF | 不处理 | 结束标记必须顶格,前面不能有空格或 Tab |
<<-EOF | 去掉行首 Tab | 内容和结束标记前可以有 Tab,但不能是空格 |
普通写法:
| |
缩进写法:
| |
需要注意:<<-EOF 只处理 Tab,不处理空格。下面写法如果 EOF 前是空格,仍然会失败。
| |
常见报错:
| |
原因:Shell 一直没有找到合法结束标记,只能读到文件结尾。
2.6 配合 sudo 写 root 文件
下面写法经常失败:
| |
原因:sudo 只作用于 cat,重定向 > 由当前 Shell 执行。当前用户没有权限写 /etc/app.conf。
推荐使用 tee:
| |
追加写入:
| |
2.7 配合 ssh 远程执行
在本机展开变量:
| |
在远程机器展开变量:
| |
区别:
| 写法 | 变量在哪里展开 |
|---|---|
<<EOF | 本机 Shell 先展开,再发送给远程 |
<<'EOF' | 本机不展开,远程 Shell 执行时再展开 |
2.8 常见错误
| 错误 | 原因 | 修复 |
|---|---|---|
wanted \EOF`` | 结束标记没被识别 | 确认结束标记顶格,且无空格 |
| 变量被提前替换 | 使用了 <<EOF | 改为 <<'EOF' |
sudo cat > file 权限失败 | 重定向由当前 Shell 执行 | 改用 sudo tee |
<<-EOF 仍失败 | 行首是空格不是 Tab | 改为 Tab 或顶格 |
| 内容中恰好出现 EOF | 提前结束 | 换一个更独特的结束标记 |
3.总结
- Here Document 用于把多行文本作为命令的标准输入;
EOF只是结束标记,可以自定义,不是固定关键字;<<EOF默认会展开变量和命令,<<'EOF'会原样输出;<<-EOF只会去掉行首 Tab,不会去掉空格;- 写 root 权限文件时,不要用
sudo cat > file,应使用sudo tee。