在日常的系统管理和自动化脚本编写中,你是否曾经遇到过这样的尴尬时刻:需要向某个命令传递一大段多行文本,或者是在脚本中生成临时的配置文件?这时候,如果使用 echo 命令一行行地拼接,代码不仅会变得冗长难看,而且维护起来简直是一场噩梦。
别担心,Shell 编程中有一个非常强大但常被初学者忽视的特性——Here Document(此处文档)。它就像是一个“嵌入在脚本中的输入流”,允许我们直接在脚本内部编写多行数据,并将它们作为标准输入传递给命令。在这篇文章中,我们将深入探讨 Here Document 的核心概念、语法细节,并结合 2026 年的最新开发理念,看看如何将这一“老古董”特性应用于现代化的 DevOps 和 AI 辅助开发工作流中。
什么是 Here Document?
简单来说,Here Document 是一种 I/O 重定向机制,它允许我们将一段多行文本直接“内联”在脚本中,并将这段文本作为标准输入传递给任何命令。想象一下,你不再需要创建临时的文本文件来存储数据,也不需要使用繁琐的引号来处理跨行字符串,Here Document 让这一切变得极其自然和流畅。
它的基本结构非常直观:我们使用一个特殊的分隔符来标记输入的开始和结束。Shell 会将这两个标记之间的所有内容原封不动地“喂”给指定的命令。下面,让我们从一个最经典的例子开始,看看它是如何工作的。
基础语法与结构解析
首先,我们需要理解 Here Document 的解剖结构。它的标准语法如下:
command << DELIMITER
line 1
line 2
...
DELIMITER
这里的 INLINECODE726a2b18 是任何能够接收标准输入的 Linux 命令(如 INLINECODE31ed05b0, INLINECODE13bb6f1c, INLINECODEab6140d1, INLINECODEd717047a 等)。INLINECODE8475d9bb 操作符告诉 Shell:“嘿,重定向即将开始!”而 DELIMITER(分隔符)则是一个我们自定义的字符串,它充当了输入块的“守门员”。Shell 会读取输入行,直到它在一个单独的行上再次看到这个确切的分隔符。
> 专业提示:虽然你可以使用任何字符串作为分隔符,但约定俗成(也是一种最佳实践)是使用大写的 INLINECODEe13e83ad(End Of File),因为这能极大地提高代码的可读性。当然,你也可以使用 INLINECODEacf319f9 或 STOP_HERE,只要始末保持一致即可。
#### 实战示例 1:多行文本排序
让我们来看一个具体的例子。假设我们有一个用户列表,想要使用 INLINECODE1e1d24eb 命令对其进行排序。如果没有 Here Document,我们可能需要将这些名字放入一个文件中,然后调用 INLINECODE3a835b3e。但现在,我们可以直接在脚本中完成:
#!/bin/bash
# 脚本:使用 here document 对用户列表进行排序
# Shebang 行,指定解释器
#!/bin/bash
# 使用 here document 将多行数据传递给 sort 命令
# 所有的行直到 EOF 都会被作为输入传递给 sort
sort << EOF
John Doe
Jane Doe
Zoe Alan
Jim Smith
Jane Smith
EOF
当我们运行这段脚本时,INLINECODEfef568da 命令接收到了夹在两个 INLINECODE58267fba 之间的所有文本,并按字母顺序输出:
Jane Doe
Jane Smith
Jim Smith
John Doe
Zoe Alan
代码原理解析:
-
sort:这是接收数据的命令。 -
<< EOF:这是触发器。Shell 看到这个符号后,知道接下来的行是数据,而不是要立即执行的指令。 - 数据块:中间的每一行都被忠实地记录下来。
- 结束的
EOF:注意,这行的前面绝对不能有任何空格或制表符,必须顶格写,否则 Shell 会认为它还没有结束。
进阶技巧:在变量中捕获多行文本
Here Document 不仅仅可以用于直接传递命令,它还是一种在变量中存储大段文本(如 HTML、SQL 查询或邮件模板)的优雅方式。我们可以通过命令替换 $(...) 将 Here Document 的输出赋值给一个变量。
#### 实战示例 2:构建消息模板
#!/bin/bash
# 脚本:使用 cat 和 here document 构建多行消息
# 将 here document 的输出直接赋值给变量 message
# 注意:结束的 EOF 必须顶格
message=$(cat << EOF
尊敬的用户,你好:
这是一条由 Bash 脚本自动生成的系统通知。
系统将在今晚 24:00 进行例行维护。
祝好,
系统管理员
EOF
)
# 打印变量内容
echo "正在发送消息..."
echo "$message"
为什么这样做更好?
相比于使用 message="Line 1 这种难以阅读的写法,Here Document 让文本内容在代码中保持了原本的格式。这对于编写生成 HTML 页面的脚本尤其有用,因为你可以在脚本中直接缩进 HTML 标签,而不用担心 Shell 的转义字符问题。
Line 2"
必须掌握的细节:Tab 键的处理 (<<-)
在编写结构化良好的 Shell 脚本时,我们通常会对代码进行缩进(比如 if 语句或循环内部)。但是,标准的 Here Document 有一个严格的要求:结束分隔符必须顶格写。这往往会破坏我们漂亮的代码缩进。
为了解决这个问题,Shell 为我们提供了 INLINECODE75359a01 操作符。只需在 INLINECODEfe393d24 后面加一个连字符,Shell 就会在读取输入时忽略行首的制表符。注意,是忽略制表符,而不是空格。
#### 实战示例 3:保持代码缩进的美观性
#!/bin/bash
# 脚本:演示 <<- 的使用,忽略行首制表符
# 如果这里是真实的逻辑判断
if true; then
# 使用 <<- 允许我们在内容中使用 Tab 缩进
# 注意:结束的 EOF 也可以有 Tab 缩进了!
cat <<- EOF
这是一行前面的 Tab,会被保留。
这一行前面的空格也会被保留(但通常我们用 Tab)。
只要内容缩进统一,代码看起来就非常整洁。
EOF
fi
关键点:使用 <<- 后,你可以使用 Tab 键将 Here Document 的内容和结束符向右缩进,使其与周围的代码块对齐。这极大地提高了脚本的可读性,特别是当 Here Document 嵌套在循环或条件语句中时。
禁用变量替换:保持文本原样 (<<'EOF')
有时候,我们在 Here Document 中包含的内容包含特殊的符号,比如 INLINECODEdf6f3d2b 或反引号 INLINECODEc3fdd951$INLINECODE48e402daftpINLINECODE9a415af0wallINLINECODEe09a29bfwallINLINECODE083399b0mysql -e "single command"INLINECODEba813750EOFINLINECODEae0f20df\rINLINECODEf4394697syntax error: unexpected end of fileINLINECODEff37757cEOFINLINECODE150ff58cEOF\rINLINECODE798b1605dos2unixINLINECODE8df1f336–INLINECODE68af0cefcore.autocrlfINLINECODE0b1456efinputINLINECODEf98d9ef1<<EOFINLINECODE81a87f18whileINLINECODEbff5c9edecho "…" | commandINLINECODEc435d0e5command < <(cat …)INLINECODE18279baf$INLINECODE2664fd18\INLINECODE44c8a764$CURRENTUSERINLINECODE3c2a15f4\$HOME 会被输出为 $HOME`。
总结:从脚本编写到工程艺术的升华
在这篇文章中,我们从最基础的结构语法出发,一直探索到 2026 年企业级环境下的安全实践和性能考量。我们发现,Here Document 不仅仅是一个语法糖,它体现了一种“代码即数据”的优雅哲学。
相比于通过管道传递复杂的引用字符串,或者创建无数个临时文件,Here Document 让我们可以将数据和逻辑紧密结合在一起。它让我们编写的脚本更像是一篇流畅的文章,而不是杂乱无章的字符堆砌。
下一步建议:
下次当你使用像 Cursor 或 Windsurf 这样的现代 IDE 编写脚本时,试着让 AI 帮你重构一段复杂的字符串拼接代码为 Here Document。你会发现,代码不仅变得易读了,AI 也能更好地理解你的意图,从而提供更精准的补全。
祝你在 Bash 编程的旅程中,不仅能写出高效的代码,更能享受代码之美!