目录
Please enable Javascript to view the contents

shell基础-Here Document与EOF用法

 ·  ☕ 3 分钟
核心结论说明
EOF 不是固定关键字它只是 here document 的结束标记,可以换成任意字符串
<<EOF 会把多行文本作为标准输入常与 catsshmysqltee 配合使用
<<-EOF 只会去掉 Tab,不会去掉空格结束标记前如果是空格,仍然无法识别
<<'EOF' 会关闭变量替换适合生成包含 $VAR、反引号、命令替换的原样文本

1.简介

Here Document 是 Shell 中用于书写多行输入的一种语法。

常见写法:

1
2
3
command <<EOF
multi line text
EOF

EOF 是 End Of File 的缩写,但在这里不是固定关键字,只是人为约定的结束标记。可以换成 ABCENDSQLCONFIG 等任意字符串。

2.说明

2.1 基本语法

语法:

1
2
3
command <<MARKER
content
MARKER

执行时,Shell 会把 MARKER 中间的内容作为 command 的标准输入。

示例:

1
2
3
cat <<EOF
hello
EOF

输出:

1
hello

等价理解:cat 本来从标准输入读取内容,here document 临时提供了一段标准输入。

2.2 EOF 可以自定义

EOF 只是结束标记,不是语法关键字。

1
2
3
cat <<END
hello
END

也可以用更有语义的标记:

1
2
3
cat <<SQL
select * from user;
SQL

建议:

场景推荐标记
普通文本EOF
SQLSQL
YAML 配置YAML
Nginx 配置NGINX
JSONJSON

2.3 写入文件:覆盖与追加

覆盖写入:

1
2
3
4
cat > app.conf <<EOF
server_port=8080
log_level=info
EOF

追加写入:

1
2
3
cat >> app.conf <<EOF
feature_flag=true
EOF

也可以把重定向写在后面:

1
2
3
4
cat <<EOF > app.conf
server_port=8080
log_level=info
EOF

两种写法效果一样,但更推荐把重定向写在命令后面第一种形式,便于一眼看出目标文件。

2.4 变量替换与原样输出

默认情况下,here document 内容会进行变量替换、命令替换。

1
2
3
4
5
name=hex
cat <<EOF
hello $name
now: $(date +%F)
EOF

输出类似:

1
2
hello hex
now: 2026-06-23

如果希望原样输出,不展开变量和命令,需要给结束标记加引号。

1
2
3
4
cat <<'EOF'
hello $name
now: $(date +%F)
EOF

输出:

1
2
hello $name
now: $(date +%F)
生成脚本、YAML、systemd unit、Nginx 配置时,如果内容中包含 $变量,优先使用 <<'EOF',避免被当前 Shell 提前展开。

2.5 <<EOF<<-EOF

两者区别:

写法行首缩进处理说明
<<EOF不处理结束标记必须顶格,前面不能有空格或 Tab
<<-EOF去掉行首 Tab内容和结束标记前可以有 Tab,但不能是空格

普通写法:

1
2
3
cat <<EOF
hello
EOF

缩进写法:

1
2
3
4
5
if true; then
	cat <<-EOF
	hello
	EOF
fi

需要注意:<<-EOF 只处理 Tab,不处理空格。下面写法如果 EOF 前是空格,仍然会失败。

1
2
3
cat <<-EOF
hello
  EOF

常见报错:

1
warning: here-document at line 1 delimited by end-of-file (wanted `EOF')

原因:Shell 一直没有找到合法结束标记,只能读到文件结尾。

2.6 配合 sudo 写 root 文件

下面写法经常失败:

1
2
3
sudo cat > /etc/app.conf <<EOF
port=8080
EOF

原因:sudo 只作用于 cat,重定向 > 由当前 Shell 执行。当前用户没有权限写 /etc/app.conf

推荐使用 tee

1
2
3
cat <<EOF | sudo tee /etc/app.conf >/dev/null
port=8080
EOF

追加写入:

1
2
3
cat <<EOF | sudo tee -a /etc/app.conf >/dev/null
feature=true
EOF

2.7 配合 ssh 远程执行

在本机展开变量:

1
2
3
4
5
host=server01
ssh root@remote <<EOF
hostname
mkdir -p /data/$host
EOF

在远程机器展开变量:

1
2
3
4
ssh root@remote <<'EOF'
host=$(hostname)
mkdir -p /data/$host
EOF

区别:

写法变量在哪里展开
<<EOF本机 Shell 先展开,再发送给远程
<<'EOF'本机不展开,远程 Shell 执行时再展开

2.8 常见错误

错误原因修复
wanted \EOF``结束标记没被识别确认结束标记顶格,且无空格
变量被提前替换使用了 <<EOF改为 <<'EOF'
sudo cat > file 权限失败重定向由当前 Shell 执行改用 sudo tee
<<-EOF 仍失败行首是空格不是 Tab改为 Tab 或顶格
内容中恰好出现 EOF提前结束换一个更独特的结束标记

3.总结

  1. Here Document 用于把多行文本作为命令的标准输入;
  2. EOF 只是结束标记,可以自定义,不是固定关键字;
  3. <<EOF 默认会展开变量和命令,<<'EOF' 会原样输出;
  4. <<-EOF 只会去掉行首 Tab,不会去掉空格;
  5. 写 root 权限文件时,不要用 sudo cat > file,应使用 sudo tee

4.参考

分享

Hex
作者
Hex
CloudNative Developer