<<
与 <<-
与 <<<
多解说笔记250722自测代码: (脚本必须将 CRLF
换成 LF
)
#!/bin/bash
tee << EOF
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
EOF
tee <<< "三个小于号(<<<)用于单行, 在这里既用于展示<<<的用法, 也用于分割上面↑↑↑和下面↓↓↓的内容 ------ 顺便实验Unicode字符兼容性"
tee <<- EOF
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
EOF
在 fedora 42 上的结果: <<
的空格和tab都保持原样, <<-
的空格保持原样, tab被<<-
吃掉了
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
三个小于号(<<<)用于单行, 在这里既用于展示<<<的用法, 也用于分割上面↑↑↑和下面↓↓↓的内容 ------ 顺便实验Unicode字符兼容性
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
在 Ubuntu24.04 上的结果: <<
的空格和tab都保持原样, <<-
的空格保持原样, tab被<<-
吃掉了
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
三个小于号(<<<)用于单行, 在这里既用于展示<<<的用法, 也用于分割上面↑↑↑和下面↓↓↓的内容 ------ 顺便实验Unicode字符兼容性
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
在 AlmaLinux9.6 上的结果: <<
的空格和tab都保持原样, <<-
的空格保持原样, tab被<<-
吃掉了
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
三个小于号(<<<)用于单行, 在这里既用于展示<<<的用法, 也用于分割上面↑↑↑和下面↓↓↓的内容 ------ 顺便实验Unicode字符兼容性
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
在 Debian10.12 上的结果: <<
的空格和tab都保持原样, <<-
的空格保持原样, tab被<<-
吃掉了
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
三个小于号(<<<)用于单行, 在这里既用于展示<<<的用法, 也用于分割上面↑↑↑和下面↓↓↓的内容 ------ 顺便实验Unicode字符兼容性
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
在 Debian12 上的结果: <<
的空格和tab都保持原样, <<-
的空格保持原样, tab被<<-
吃掉了
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
三个小于号(<<<)用于单行, 在这里既用于展示<<<的用法, 也用于分割上面↑↑↑和下面↓↓↓的内容 ------ 顺便实验Unicode字符兼容性
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
在 Ubuntu16.4.7 上的结果: <<
的空格和tab都保持原样, <<-
的空格保持原样, tab被<<-
吃掉了
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
三个小于号(<<<)用于单行, 在这里既用于展示<<<的用法, 也用于分割上面↑↑↑和下面↓↓↓的内容 ------ 顺便实验Unicode字符兼容性
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
在 Ubuntu18.04.6 上的结果: <<
的空格和tab都保持原样, <<-
的空格保持原样, tab被<<-
吃掉了
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
三个小于号(<<<)用于单行, 在这里既用于展示<<<的用法, 也用于分割上面↑↑↑和下面↓↓↓的内容 ------ 顺便实验Unicode字符兼容性
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
在 CentOS7 上的结果: <<
的空格和tab都保持原样, <<-
的空格保持原样, tab被<<-
吃掉了
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
三个小于号(<<<)用于单行, 在这里既用于展示<<<的用法, 也用于分割上面↑↑↑和下面↓↓↓的内容 ------ 顺便实验Unicode字符兼容性
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
在 CentOS6 上的结果: <<
的空格和tab都保持原样, <<-
的空格保持原样, tab被<<-
吃掉了
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
三个小于号(<<<)用于单行, 在这里既用于展示<<<的用法, 也用于分割上面↑↑↑和下面↓↓↓的内容 ------ 顺便实验Unicode字符兼容性
0BlankBefore
2BlankBefore
4BlankBefore
6BlankBefore
8BlankBefore
0TabBefore
2TabBefore
4TabBefore
6TabBefore
8TabBefore
<<
与 <<-
<<
vs <<-
:Here Document 的缩进处理详解
在 Linux Shell 中,<<
和 <<-
都用于创建 Here Document(嵌入文档),但它们在缩进处理上有本质区别:
核心区别对比
特性 | << (标准形式) |
<<- (缩进处理形式) |
---|---|---|
缩进处理 | 保留所有空白(含缩进) | 仅去除前导制表符(Tab) |
结束标记要求 | 必须顶格无缩进 | 允许前有制表符 |
空格处理 | 保留空格 | 不处理空格 |
典型用例 | 需要保留格式的内容 | 美化脚本中的长文档 |
兼容性 | 所有 POSIX Shell | 所有 POSIX Shell |
内容完整性 | 完全保留原始格式 | 可能改变缩进结构 |
详细解析
1. <<
(标准 Here Document)
cat << END
保留所有缩进
空格也保留
END # 必须顶格
输出: 保留所有缩进
空格也保留
2. <<-
(缩进处理 Here Document)
cat <<- TABBED
第一行(Tab缩进)
混合缩进:Tab+空格
TABBED # 前有Tab
输出:第一行(Tab缩进)
混合缩进:Tab+空格 # 空格保留
关键注意事项
1. Tab 与空格的区别
# 正确:Tab 缩进会被移除
cat <<- EOF
Tab缩进内容
EOF # 前有Tab → 有效
# 错误:空格缩进不会被处理
cat <<- EOF
空格缩进内容 # 4个空格
EOF # 前有空格 → 无效(报错)
2. 混合缩进问题
cat <<- MIXED
Tab行 → 缩进移除
空格行 → 保留空格
MIXED # 前有Tab
输出:
Tab行 → 缩进移除
空格行 → 保留空格 # 4空格保留
3. 嵌套使用
if true; then
# 外层缩进
cat <<- INNER
内层Tab缩进
INNER # 前有Tab
fi
输出:内层Tab缩进
(无缩进)
使用场景指南
何时用 <<
✅
# 1. 需要保留格式的文档
cat << FORMATTED > poem.txt
静夜思
床前明月光
疑是地上霜
FORMATTED
# 2. 空格敏感的配置
cat << SPACE > config.yml
indentation:
level: 4 # 必须4空格
SPACE
何时用 <<-
✅
# 1. 脚本美化(使用Tab缩进)
if [ "$verbose" = true ]; then
cat <<- VERBOSE
[DEBUG] 详细日志:
用户: $USER
时间: $(date)
VERBOSE
fi
# 2. SQL查询(可读性优先)
mysqldump <<- SQL
SELECT *
FROM users
WHERE active=1
SQL # 结束标记对齐
何时避免 <<-
⚠️
# 1. 需要保留Tab的场景
cat <<- TABS > tabs.txt
重要制表符: → 这里Tab会被保留
但行首Tab会被移除
TABS
# 2. 空格缩进的环境
# (如Python脚本)
技术原理图解
最佳实践
统一缩进风格:
# 推荐:全脚本使用Tab缩进
function show_info() {
cat <<- INFO
系统信息:
用户: $USER
时间: $(date)
INFO
}
禁用替换的缩进文档:
# 单引号+缩进处理
cat <<- 'SQL' > query.sql
SELECT *
FROM ${table} # 原样保留
SQL
错误处理技巧:
# 检查结束标记是否有效
if ! cat <<- TEST
内容(4空格)
TEST # 故意用空格缩进
then
echo "错误:结束标记前有空格!" >&2
exit 1
fi
多级缩进方案:
main() {
local indent=" " # 4空格
cat <<- EOF | sed "s/^/$indent/"
一级缩进内容
EOF
}
<<
与 <<<
<<
vs <<<
:多行文档 vs 单行字符串输入详解
在 Linux Shell 中,<<
(Here Document)和 <<<
(Here String)都是输入重定向操作符,但它们在输入类型、处理方式和使用场景上有本质区别:
核心对比表
特性 | << (Here Document) |
<<< (Here String) |
---|---|---|
输入类型 | 多行文档 | 单行字符串 |
语法 | cmd << DELIM 内容行... DELIM |
cmd <<< "字符串" |
结束标记 | 必需 | 不需要 |
变量替换 | 默认启用(除非定界符被引用) | 总是启用 |
末尾换行符 | 保留原始换行 | 自动添加一个换行符 |
内存占用 | 较高(生成临时文件/管道) | 较低(直接传递字符串) |
POSIX 标准 | ✔️ 完全兼容 | ❌ Bash/Zsh 扩展 |
典型用例 | 脚本、配置、SQL 等结构化文本 | 命令行参数、简单字符串处理 |
详细解析
1. <<
(Here Document)
# 多行文档输入
cat << EOF
第一行
第二行: $HOME
EOF
输出:第一行
第二行: /home/user
2. <<<
(Here String)
# 单行字符串输入
wc -c <<< "Hello" # 计算字节数(包含自动添加的换行符)
输出:6
(“Hello” 5字节 + \n 1字节)关键区别演示
1. 输入结构差异
# << 保留多行结构
cat << DOC
Line 1
Line 2
DOC
# <<< 视为单行
cat <<< "Line 1
Line 2" # 输出: Line 1\nLine 2
2. 换行符处理
# << 保留原始换行
tr '\n' ':' << END
a
b
END # 输出: a:b:
# <<< 自动添加换行
tr '\n' ':' <<< "text" # 输出: text:
3. 性能差异
# 处理大文本时 <<< 更高效
time for i in {1..1000}; do
cat <<< "$(seq 1 1000)"
done > /dev/null
time for i in {1..1000}; do
cat << END
$(seq 1 1000)
END
done > /dev/null
<<<
版本通常快 2-3 倍
使用场景指南
何时用 <<
✅
# 1. 生成配置文件
cat > app.conf << CONFIG
[server]
port=8080
log_dir=/var/log
CONFIG
# 2. 执行多行命令
ssh user@host << SSH_CMD
cd /app
git pull
sudo systemctl restart service
SSH_CMD
# 3. 保留格式的文本
cat << POEM
静夜思
床前明月光
疑是地上霜
POEM
何时用 <<<
✅
# 1. 快速字符串处理
base64 <<< "encode this" # 编码
md5sum <<< "text" # 计算哈希
# 2. 避免管道操作
grep "error" <<< "$log_content" # 优于 echo "$log" | grep
# 3. 命令行参数传递
docker exec -i container sh <<< "ls -l"
# 4. 数学计算
bc <<< "2^20" # 计算 2 的 20 次方
何时避免 ⚠️
# << 不适合
echo "单行内容" | cmd # 简单单行用管道更直观
# <<< 不适合
cat <<< "多行
内容" # 多行文本应使用 <<
进阶技巧
1. 混合使用
# 动态生成 SQL 查询
query=$(cat << SQL
SELECT * FROM users
WHERE name="$1"
SQL
)
mysql <<< "$query" # 执行查询
2. 禁用替换的 Here String
# 使用单引号禁用替换
cat <<< '$HOME' # 输出 $HOME
3. 二进制数据处理
# <<< 处理二进制 (base64)
base64 -d <<< "SGVsbG8K" # 解码后输出 Hello
4. 性能优化
# 避免多次调用 <<<
mapfile -t arr <<< "$(seq 1 100)" # 一次读入数组
特殊注意事项
换行符陷阱:
# <<< 自动添加换行
printf "%s" "$(seq 3)" | wc -c # 输出 3
wc -c <<< "$(seq 3)" # 输出 4 (1+2+3+\n)
变量作用域:
# << 在新子shell中执行替换
var=outer
cat << 'END'
$var # 输出 outer
END
兼容性解决方案:
# 替代 <<< 的 POSIX 方法
echo "string" | cmd # 标准管道
cmd << EOF # Here Document
string
EOF
大文本处理:
# 超过 64KB 的文本避免用 <<<
# 改用临时文件或 <<
通过理解这些核心区别,您可以根据具体场景选择最高效、最合适的输入重定向方式。多行结构化内容首选 <<
,单行字符串处理则优先考虑 <<<
。
<<
、<<-
、<<<
详解 <<
、<<-
、<<<
详解
在 Linux Shell 中,这三个运算符都与输入重定向相关,但功能和行为有显著差异:
1. <<
(标准 Here Document)
command << DELIMITER
文档内容...
DELIMITER
DELIMITER
必须单独一行且无缩进cat << END
第一行
第二行: $HOME
END
输出:第一行
第二行: /home/user
2. <<-
(带缩进处理的 Here Document)
command <<- DELIMITER
文档内容...
DELIMITER # 前导制表符会被忽略
cat <<- INDENTED
第一行(有Tab缩进)
第二行(有Tab缩进)
INDENTED # 前有Tab
输出(无缩进):第一行(有Tab缩进)
第二行(有Tab缩进)
3. <<<
(Here String)
command <<< "字符串内容"
# 单行字符串输入
wc -c <<< "Hello World" # 计算字节数(包含换行符)
# 带变量替换
name="Alice"
grep "li" <<< "Hello $name" # 输出 Hello Alice
三者的核心区别
特性 | << |
<<- |
<<< |
---|---|---|---|
输入类型 | 多行文档 | 带缩进的多行文档 | 单行字符串 |
结束标记 | 必需(DELIMITER ) |
必需(DELIMITER ) |
不需要 |
缩进处理 | 保留所有空白 | 忽略前导制表符(Tab) | 不适用 |
变量替换 | 默认启用(除非引用) | 默认启用(除非引用) | 总是启用 |
自动换行符 | 保留原始换行 | 保留原始换行 | 末尾自动添加换行符 |
典型用例 | 配置文件、SQL查询 | 美化脚本中的长文档 | 单行命令输入 |
POSIX 兼容性 | ✔️ 完全兼容 | ✔️ 完全兼容 | ❌ Bash/Zsh 扩展 |
使用场景对比
1. 多行内容 → 用 <<
或 <<-
# 生成配置文件 (<<)
cat > app.conf << CONFIG
server_port=8080
log_dir=/var/log
CONFIG
# 带缩进的脚本 (<<-)
if true; then
cat <<- EOF
缩进内容
可读性更好
EOF # 前有Tab
fi
2. 单行内容 → 用 <<<
# 快速字符串处理
base64 <<< "encode this" # 编码字符串
md5sum <<< "text" # 计算MD5
# 避免管道和echo
grep "error" <<< "$logs" # 直接搜索变量内容
3. 混合使用
# Here Document + Here String
sql_query=$(cat << EOF
SELECT * FROM users
WHERE name="$1"
EOF
)
mysql <<< "$sql_query" # 执行SQL
特殊注意事项
<<-
的陷阱:
# 错误:空格缩进不会被忽略
cat <<- EOF
空格缩进内容 # 保留空格
EOF # 必须用Tab缩进
<<<
的换行符:
# 包含换行符计数
str="hello"
wc -c <<< "$str" # 输出 6 (hello + \n)
性能差异:
# <<< 比管道更高效
tr 'a-z' 'A-Z' <<< "text" # 优于 echo "text" | tr ...
嵌套技巧:
# 嵌套 Here Document
cat << 'OUTER' | ssh remote
cat << INNER
内部文档
INNER
OUTER
验证脚本
#!/bin/bash
echo "===== << 示例 ====="
cat << STANDARD
标准文档
保留缩进: $HOME
STANDARD
echo "===== <<- 示例 ====="
cat <<- STRIPPED
Tab缩进文档
保留内容缩进
STRIPPED # 前有Tab
echo "===== <<< 示例 ====="
wc -c <<< "测试字符串"
输出:
===== << 示例 =====
标准文档
保留缩进: /home/user
===== <<- 示例 =====
Tab缩进文档
保留内容缩进
===== <<< 示例 =====
14 # 中文字符+换行符的字节数
<<
、<<-
和 <<<
是三种不同的输入重定向操作符,各有特定的用途和行为。以下是详细解析和对比: 1. <<
(Here Document)
command << DELIMITER
文本行1
文本行2
...
DELIMITER
'DELIMITER'
禁用)DELIMITER
必须独占一行且无前导空格cat << END
Line 1 # 缩进被保留
Line 2
END
输出: Line 1
Line 2
2. <<-
(Here Document with Tab Suppression)
command <<- DELIMITER
文本行1 # 行首Tab被忽略
文本行2
DELIMITER
<<
cat <<- END
Tabbed Line 1 # 行首Tab被删除
Tabbed Line 2
END # 终止符可缩进
输出:Tabbed Line 1
Tabbed Line 2
cat <<- END
Space + Tab→Line # 仅删除Tab,保留空格
END
输出: Space + Tab→Line # 开头的4个空格保留
3. <<<
(Here String)
command <<< "字符串内容"
echo
)echo "str" | command
更高效(避免子shell)# 基本用法
wc -c <<< "Hello" # 统计字节数(包含换行符)
# 输出:6("Hello" + \n)
# 变量替换
name="Alice"
grep "li" <<< "$name" # 输出:Alice
# 命令替换
awk '{print $2}' <<< "Apple Banana Cherry" # 输出:Banana
三者的核心对比
特性 | << (Here Document) |
<<- (Tab-Suppressed) |
<<< (Here String) |
---|---|---|---|
输入类型 | 多行文本块 | 多行文本块 | 单行字符串 |
行首空白处理 | 保留所有空白 | 仅删除行首 Tab | 不适用(单行) |
终止符要求 | 必须独占一行(无缩进) | 可缩进(仅限 Tab) | 不需要终止符 |
变量替换 | 支持(除非 'EOF' ) |
支持(除非 'EOF' ) |
支持 |
末尾换行符 | 按原样保留 | 按原样保留 | 自动添加 |
典型应用场景 | 生成配置文件、多行脚本 | 缩进美观的多行文本 | 单行文本处理、避免管道 |
使用场景详解
<<
最佳场景:多行内容处理
# 生成配置文件
cat > app.conf << CONFIG
server {
port=8080
host="$(hostname)"
}
CONFIG
# 执行多行SQL
mysql << SQL
USE mydb;
SELECT * FROM users;
SQL
<<-
最佳场景:脚本内美化缩进
function deploy() {
ssh server <<- DEPLOY
cd /app
git pull
systemctl restart app
DEPLOY # 终止符可对齐缩进
}
<<<
最佳场景:单行字符串处理
# 检查字符串是否包含子串
grep "error" <<< "$log_msg"
# 数学计算(避免管道)
bc <<< "2^20" # 计算2的20次方
# 快速测试命令
awk '{print toupper($0)}' <<< "hello" # 输出:HELLO
特殊注意事项
<<-
的陷阱:
Ctrl+V Tab
输入真实 Tab<<<
的换行符:
echo -n "Hello" | wc -c # 输出:5(无换行)
wc -c <<< "Hello" # 输出:6(含\n)
wc -c <<< -n "Hello" # 错误!<<< 不支持选项
性能对比:
# 高效方式(无子shell)
md5sum <<< "$data"
# 低效方式(创建子shell)
echo "$data" | md5sum
嵌套使用:
# 混合使用示例
cat << EOF1
Outer Document
$(cat << EOF2
Inner Document
EOF2
)
EOF1
总结选择指南
需求 | 推荐操作符 | 示例 |
---|---|---|
传递多行文本(保留格式) | << |
cat << END |
多行文本需代码缩进 | <<- |
cat <<- EOF (使用 Tab 缩进) |
传递单行字符串 | <<< |
grep "pat" <<< "$var" |
避免管道开销 | <<< |
wc -l <<< "$lines" |
脚本内美观的多行代码块 | <<- |
函数内缩进的 Here Document |
掌握这三者的区别能显著提升 Shell 脚本的可读性和效率,特别是在处理配置文件生成、远程命令执行和字符串操作时。
<<
、<<-
和 <<<
是三种不同的重定向操作符,各有特定用途。以下是详细对比: 1. <<
(标准 Here Document)
命令 << 分隔符
<< 'EOF'
)cat << END
Line 1
Line 2
END
2. <<-
(带缩进的 Here Document)
命令 <<- 分隔符
cat <<- EOF
This line has Tab indent # 实际输出会保留缩进
EOF # 结束符前有 Tab(会被忽略)
输出: This line has Tab indent
3. <<<
(Here String)
命令 <<< "字符串"
grep "hello" <<< "hello world" # 输出: hello world
wc -l <<< "$(ls)" # 统计当前目录文件数
核心对比表
特性 | << (Here Document) |
<<- (缩进 Here Doc) |
<<< (Here String) |
---|---|---|---|
输入类型 | 多行文本 | 多行文本 | 单行字符串 |
结束标记 | 需单独行分隔符 | 需单独行分隔符 | 无结束标记 |
缩进处理 | 结束符必须顶格 | 可忽略结束符前 Tab | 不适用 |
变量替换 | ✅ (默认) | ✅ (默认) | ✅ |
POSIX 标准 | ✅ | ✅ | ❌ (Bash 扩展) |
典型场景 | 生成配置文件 | 美化脚本缩进 | 单行命令输入 |
使用场景示例
1. <<
(多行配置生成)
cat > app.conf << CONFIG
server {
port: 8080
host: $HOSTNAME
}
CONFIG
2. <<-
(带缩进的脚本)
if true; then
cat <<- EOF
Indented message
Current user: $USER
EOF # 结束符前有 Tab
fi
3. <<<
(单行字符串处理)
# 快速字符串处理
base64 <<< "hello" # 编码字符串
md5sum <<< "secret" # 计算 MD5
grep "error" <<< "$logs" # 搜索变量内容
重要注意事项
缩进规则:
<<-
只忽略 Tab,不忽略空格# 错误示例(使用空格缩进)
cat <<- EOF
This will FAIL # 空格缩进
EOF # 不会被识别为结束符
变量作用域:
# Here Document 在子 shell 执行
var="outer"
cat << EOF | grep "inner"
var="inner" # 修改的 var 不影响父 shell
EOF
echo $var # 输出: outer
性能差异:
<<<
比 echo |
管道更高效(避免创建子进程)# 更高效的单行处理
wc -c <<< "test" # 优于 echo "test" | wc -c
最佳实践:
- 需要多行内容 → 用
<<
或<<-
- 需要单行内容 → 用
<<<
- 脚本美化缩进 → 用
<<-
+ Tab 缩进
<<
、<<-
和 <<<
是三种不同的输入重定向操作符,各自有特定的用途和行为: 1. <<
(标准 Here Document)
command << DELIMITER
text line 1
text line 2
DELIMITER
DELIMITER
必须单独成行且前后无空格$var
)和命令替换($(cmd)
)\$
防止变量展开)示例:
cat << END
This indentation # 缩进会被保留
User: $USER # 变量会被展开
END
2. <<-
(带缩进处理的 Here Document)
command <<- DELIMITER
text line 1
text line 2
DELIMITER
<<
相同(会展开变量)示例:
cat <<- EOF
Indented with Tab # 前导 Tab 会被删除
User: $USER # 变量仍会被展开
EOF # 结束标记可缩进(必须用 Tab)
3. <<<
(Here String)
command <<< "string"
-n
选项)示例:
grep "root" <<< "$(cat /etc/passwd)"
wc -l <<< "one two three" # 输出 1(统计行数)
三者的对比总结
特性 | << (Here Document) |
<<- (Indented Here Doc) |
<<< (Here String) |
---|---|---|---|
输入类型 | 多行文本块 | 多行文本块 | 单行字符串 |
结束标记 | 必需 (如 EOF ) |
必需 (如 EOF ) |
不需要 |
变量展开 | ✅ 默认展开 | ✅ 默认展开 | ✅ 默认展开 |
忽略缩进 | ❌ 保留所有空白 | ✅ 仅忽略前导 Tab | ❌ 不适用 |
自动添加换行符 | ❌ 按原样输出 | ❌ 按原样输出 | ✅ 总是添加 |
典型用途 | 多行配置/脚本嵌入 | 缩进的多行内容 | 单行命令输入 |
使用场景示例
<<
(标准 Here Document):
# 生成配置文件
cat > app.conf << CONFIG
server {
listen 80;
root $WEB_ROOT; # 变量展开
}
CONFIG
<<-
(缩进 Here Document):
# 带缩进的脚本(使用 Tab 缩进)
if [ "$debug" = true ]; then
logger <<- LOG
[DEBUG] Process started
User: $USER
Time: $(date)
LOG # 缩进的结束标记
fi
<<<
(Here String):
# 单行字符串处理
md5sum <<< "hello world" # 计算字符串哈希
grep "error" <<< "$log_data" # 在变量中搜索
bc <<< "2^20" # 计算 2 的 20 次方
重要注意事项
缩进规则:
<<-
只忽略制表符(Tab),不忽略空格引号处理:
# 禁止变量展开
cat << 'EOF'
$PATH # 原样输出
EOF
# Here String 的引号
cat <<< '$PATH' # 输出: $PATH
cat <<< "$PATH" # 输出: 路径内容
换行符差异:
printf "no newline" | wc -c # 10 字符
wc -c <<< "no newline" # 11 字符(自动添加 \n)
根据需求选择合适的操作符:
<<
或 <<-
<<-
+ Tab<<<
<<
、<<-
和 <<<
是三种不同的重定向操作符,用于处理输入数据(Here Document、Here String 等)。它们的核心区别在于输入来源和格式处理方式。以下是详细对比: 1. <<
(Here Document)
功能
EOF
)。'EOF'
禁用扩展)。语法
command << EOF
输入内容...
EOF
特点
$var
)和命令替换(如 $(date)
),除非用 << 'EOF'
或 << \EOF
禁用。示例
cat << EOF
Hello, $USER!
Today is $(date).
EOF
输出:
Hello, alice!
Today is Wed Oct 25 12:34:56 UTC 2023.
2. <<-
(缩进 Here Document)
功能
<<
类似,但允许忽略每行开头的制表符(Tab)(非空格!)。语法
command <<- EOF
输入内容(每行前的Tab会被忽略)...
EOF
特点
<<
完全一致(变量扩展、命令替换等)。示例
if true; then
cat <<- EOF
This line is indented with tabs.
$USER is logged in.
EOF
fi
输出:
This line is indented with tabs.
alice is logged in.
3. <<<
(Here String)
功能
echo "string" | command
的简写)。语法
command <<< "输入字符串"
# 或
command <<< $var # 变量内容作为输入
特点
\n
或换行符拼接)。示例
# 传递字符串
grep "error" <<< "This is an error message."
# 传递变量
file_content=$(cat file.txt)
wc -c <<< "$file_content" # 统计文件字符数
关键区别总结
操作符 | 输入来源 | 多行支持 | 缩进处理 | 典型用途 |
---|---|---|---|---|
<< |
Here Document | ✅ 是 | ❌ 禁止前缀 | 传递多行文本(如配置、模板) |
<<- |
Here Document | ✅ 是 | ✅ 忽略 Tab | 缩进的多行文本(如脚本块内) |
<<< |
Here String | ❌ 否 | ❌ 无意义 | 快速传递单行字符串或变量 |
其他注意事项
Here Document 的结束标记:
<<-
忽略 Tab)。EOV
、STOP
等)。Here String 的变量扩展:
name="Alice"
echo <<< "Hello, $name!" # 错误!需去掉 `echo` 或改用 `cat <<< "Hello, $name"`
cat <<< "Hello, $name" # 正确:输出 "Hello, Alice"
性能差异:
<<<
比 echo "string" | command
更高效(少启动一个子进程)。<<
/<<-
适合大量文本输入,<<<
适合短输入。实际应用场景
<<
:生成配置文件、嵌入多行代码或文本模板。
cat << EOF | sudo tee /etc/config.conf
user = $USER
path = /data/$USER
EOF
<<-
:在 if
/for
块中保持缩进美观。
if [ -f file.txt ]; then
cat <<- EOF
File exists!
Content:
$(cat file.txt)
EOF
fi
<<<
:快速处理变量或单行输入。
# 统计单词数
wc -w <<< "This is a test."
# 传递变量给 `bc` 计算
bc <<< "2 + 2 * 3"
通过合理选择操作符,可以更高效地编写 shell 脚本并控制输入行为。
<<
、<<-
和 <<<
是三种不同的 输入重定向操作符,用于将数据传递给命令的标准输入(stdin)。它们的核心区别在于对输入内容的处理方式和用途。以下是详细对比: 1. <<
(Here Document)
用途:将多行文本(Here Document)传递给命令作为标准输入。
语法:
command << DELIMITER
多行文本内容...
DELIMITER
特点:
DELIMITER
)。DELIMITER
必须严格匹配(前后不能有空格或 Tab)。示例:
VAR="World"
cat << EOF
Hello, $VAR!
This is a Here Document.
EOF
输出:
Hello, World!
This is a Here Document.
2. <<-
(Here Document with Tab Stripping)
用途:与 <<
类似,但允许在 Here Document 中忽略前导的 Tab 字符。
语法:
command <<- DELIMITER
多行文本内容...
DELIMITER
特点:
DELIMITER
)。DELIMITER
必须严格匹配。示例:
VAR="World"
cat <<- EOF
Hello, $VAR!
This line has leading tabs.
EOF
输出:
Hello, World!
This line has leading tabs.
3. <<<
(Here String)
用途:将单行字符串(Here String)传递给命令作为标准输入。
语法:
command <<< "单行字符串"
特点:
示例:
VAR="Hello"
cat <<< "$VAR, World!"
输出:
Hello, World!
关键区别总结
操作符 | 用途 | 输入类型 | 变量替换 | 缩进处理 | 结束标记要求 |
---|---|---|---|---|---|
<< |
多行文本 | 多行 | ✅ 启用 | 保留所有缩进 | 严格匹配 |
<<- |
多行文本(忽略 Tab) | 多行 | ✅ 启用 | 仅忽略前导 Tab | 严格匹配 |
<<< |
单行字符串 | 单行 | ✅ 启用 | 无缩进 | 无结束标记 |
注意事项
结束标记的格式:
<<
和 <<-
的结束标记必须单独一行,且前后不能有空格或 Tab。cat << EOF
Content...
EOF # ❌ 错误:结束标记前有空格
变量替换控制:
DELIMITER
:cat << 'EOF'
$VAR will not be expanded.
EOF
Here String 的限制:
<<<
仅适用于单行输入,无法处理多行文本。cat <<< "Line 1
Line 2" # ❌ 错误:换行符会被截断
性能与适用场景:
<<
和 <<-
适合处理多行文本(如配置文件、模板等)。<<<
适合快速传递单行字符串(如调试或简单输入)。 实际应用场景
(1) 使用 <<
生成多行文件
cat << EOF > config.txt
# This is a configuration file
HOST=localhost
PORT=8080
EOF
(2) 使用 <<-
处理带缩进的文本
cat <<- EOF > template.sh
#!/bin/bash
# This script is indented
echo "Indented content"
EOF
(3) 使用 <<<
快速传递单行输入
grep "error" <<< "This is an error message"
总结
<<
:标准的 Here Document,适合多行文本。<<-
:Here Document 的变体,适合处理带 Tab 缩进的多行文本。<<<
:Here String,适合单行字符串输入。根据需求选择合适的操作符,可以显著提升脚本的可读性和灵活性!
<<
、<<-
和 <<<
是三种不同的输入重定向符号,用于将文本传递给命令。它们的核心区别在于处理方式、文本范围和特殊字符的解析规则。以下是详细解析: 一、<<
(Here-Document,标准形式)
基本语法
命令 << 分界符
多行文本内容
分界符
特点
$VAR
)和命令(如$(cmd)
)会被解析。
'EOF'
)。示例
NAME="Alice"
cat << EOF
Hello $NAME
当前时间:$(date +%H:%M)
EOF
输出(假设当前时间为15:30):
Hello Alice
当前时间:15:30
二、<<-
(Here-Document,忽略Tab缩进)
基本语法
命令 <<- 分界符
多行文本内容(可缩进)
分界符
特点
<<
一致。示例
cat <<- EOF
这行有Tab缩进
这行有两个Tab缩进
EOF # 结束分界符前的Tab也会被忽略
EOF
输出:
这行有Tab缩进
这行有两个Tab缩进
EOF
三、<<<
(Here-String,单行文本)
基本语法
命令 <<< "单行文本内容"
特点
echo "文本" | 命令
)。示例
# 示例1:变量替换
NAME="Alice"
grep "Alice" <<< "$NAME" # 等价于 echo "Alice" | grep "Alice"
# 示例2:保留字面量
grep "$" <<< '$VAR' # 等价于 echo '$VAR' | grep "$"
四、对比总结
符号 | 类型 | 文本范围 | 变量替换 | 缩进处理 |
---|---|---|---|---|
<< |
Here-Document | 多行 | 默认替换,可禁用 | 分界符必须顶格,保留缩进 |
<<- |
Here-Document(增强) | 多行 | 默认替换,可禁用 | 忽略行首Tab缩进 |
<<< |
Here-String | 单行 | 引号内替换 | 不支持缩进,仅一行文本 |
五、典型应用场景
<<
的场景
mysql << EOF ...
)。<<-
的场景
help() {
cat <<- EOF
用法: script.sh [选项]
-h 显示帮助
-v 显示版本
EOF
}
<<<
的场景
grep
、awk
)。echo | 命令
)。六、注意事项
EOF
和eof
是不同的标记。<<-
仅忽略Tab:若使用空格缩进,分界符仍需顶格。<<< '文本'
(单引号)禁用替换,<<< "文本"
(双引号)启用替换。通过合理选择这三种符号,可以更灵活地处理脚本中的文本输入,提高代码可读性和维护性。
<<
、<<-
和 <<<
是三种不同的输入重定向操作符,分别对应 多行文本块输入、可缩进的多行文本输入 和 单行字符串输入。以下是它们的核心区别及典型用法:核心功能对比
操作符 | 名称 | 输入类型 | 变量处理 | 典型场景 | 示例 |
---|---|---|---|---|---|
<< |
Here Document | 多行文本块 | 默认展开变量(除非加引号) | 生成配置文件、交互式命令输入 | cat << EOF 多行内容 EOF |
<<- |
缩进 Here Document | 多行文本块 | 同 << |
需缩进的多行文本(如脚本内使用) | cat <<- EOF ·Tab缩进内容 EOF |
<<< |
Here String | 单行字符串 | 默认展开变量 | 快速传递单行字符串给命令 | grep "key" <<< "字符串" |
详细解析
1. <<
(Here Document)
<< EOF
):文本中的 $变量
和 $(命令)
会被解析并替换。<< 'EOF'
):文本内容原样输出,禁止变量和命令替换。cat << EOF
Hello $USER # 输出 Hello <当前用户名>
Today is $(date)
EOF
EOF
)必须顶格独占一行,前后无空格。 2. <<-
(缩进 Here Document)
<<
基础上忽略每行开头的 Tab 制表符(⚠️ 不忽略空格),便于脚本中缩进排版。cat <<- EOF
This line starts with Tab (ignored).
EOF # 结束标记可用 Tab 缩进
→ 输出:This line starts with Tab (ignored).
(无缩进)。 3. <<<
(Here String)
echo "字符串" | command
更简洁高效。# 检查字符串是否包含 "key"
grep "key" <<< "This is a key string"
# 计算字符串的 SHA256 哈希
sha256sum <<< "text"
name="Alice"
grep "Hello" <<< "Hello $name" # 输出 Hello Alice
⚠️ 常见问题与避坑指南
<<-
对空格无效
\t
),空格会被保留,错误使用空格缩进会导致结束标记失效。结束标记冲突
EOF
,需更换唯一性标记(如 END_CONFIG
)。远程执行变量混淆
\$VAR
)避免提前解析:ssh user@host << EOF
Local: $PWD # 本地解析
Remote: \$PWD # 远程解析
EOF
。总结:按场景选择
需求 | 推荐操作符 | 示例 |
---|---|---|
动态生成多行配置(含变量) | << EOF |
生成 Nginx 配置 |
保留特殊字符的静态文本 | << 'EOF' |
输出 ${{TEMPLATE}} 模板 |
脚本内缩进的多行文本 | <<- EOF |
函数内嵌入 SQL 查询 |
快速传递单行字符串 | <<< |
校验字符串哈希值 |
通过合理选择操作符,可显著提升脚本可读性与执行效率。
<<
、<<-
和 <<<
都是用于输入重定向的操作符,但它们的行为和用途有显著区别。以下是详细解释: 1. <<
(Here Document)
行为:
用于定义多行输入块(称为 here document),内容按原样传递到命令的标准输入,保留所有空格、缩进和换行。
语法:
command << DELIMITER
输入内容
DELIMITER
示例:
cat << EOF
Hello World
This is a multi-line text.
EOF
输出:
Hello World
This is a multi-line text.
特点:
EOF
)必须单独一行且顶格书写。 2. <<-
(Indented Here Document)
行为:
与 <<
类似,但允许在定界符和内容前使用制表符(TAB)缩进。输入内容中的制表符会被自动去除(空格不会被去除)。
语法:
command <<- DELIMITER
输入内容(可用 TAB 缩进)
DELIMITER # 允许 TAB 缩进
示例:
cat <<- EOF
Hello World
This line is indented with a TAB.
EOF # 此处必须用 TAB 缩进
输出:
Hello World
This line is indented with a TAB.
特点:
3. <<<
(Here String)
行为:
将单行字符串直接传递到命令的标准输入(称为 here string)。会保留字符串中的转义字符和引号行为。
语法:
command <<< "字符串"
示例:
# 计算字符串的单词数
wc -w <<< "Hello Shell World"
输出:
3
特点:
echo "字符串" | command
更高效(无需启动子进程)。三者的关键区别
操作符 | 输入类型 | 缩进处理 | 典型场景 |
---|---|---|---|
<< |
多行块 | 保留所有缩进 | 多行文本(如生成配置文件) |
<<- |
多行块 | 去除行首 TAB 缩进 | 格式化的多行文本 |
<<< |
单行字符串 | 不处理缩进,直接传递 | 短文本快速输入 |
使用场景示例
场景 1:生成配置文件(保留缩进)
cat > config.yaml << EOF
server:
port: 8080
host: 0.0.0.0
EOF
场景 2:格式化的 SQL 脚本(自动去除缩进)
mysql <<- SQL
SELECT * FROM users
WHERE name = "John";
SQL
场景 3:快速计算字符串哈希值
md5sum <<< "password123"
常见误区
<<-
无法处理空格缩进:
只有 TAB 缩进会被自动去除,空格会保留。
<<<
的多行字符串问题:
若需传递多行内容,需显式包含换行符:
grep "key" <<< "line1\nline2\nkey=value"
定界符冲突:
Here document 的定界符避免使用常见符号(如 EOF
而非 EOF#
),否则可能意外截断输入。
根据需求选择操作符,能显著提升脚本的灵活性和可维护性。
在 Linux 的 Shell 脚本中,<<
、<<-
和 <<<
是三种不同的输入重定向语法,用于将数据传递给命令。以下是它们的详细区别和用法:
1. <<
(Here Document)
作用:将多行文本作为输入传递给命令,直到遇到指定的结束标记(如 EOF
)。
语法:
command << EOF
多行文本内容
EOF
特点:
$HOME
)和命令替换(如 $(date)
)会被解析。EOF
必须单独成行且顶格书写(不能有缩进)。END
、STOP
)。示例:
cat << EOF
当前用户:$USER
系统时间:$(date)
EOF
输出:
当前用户:root
系统时间:Mon Jul 1 12:34:56 UTC 2024
2. <<-
(Here Document with Tab Suppression)
作用:与 <<
类似,但允许忽略行首的 制表符(Tab),方便代码缩进。
语法:
command <<- EOF
多行文本内容(行首可用 Tab 缩进)
EOF
特点:
\t
),不处理空格。EOF
必须单独成行且无缩进(但文本内容可缩进)。示例:
cat <<- EOF
当前用户:$USER
系统时间:$(date)
EOF
输出:
当前用户:root
系统时间:Mon Jul 1 12:34:56 UTC 2024
3. <<<
(Here String)
作用:将单个字符串作为输入传递给命令,类似于 echo "内容" | command
。
语法:
command <<< "字符串"
特点:
示例:
grep "root" <<< "$USER"
输出:
root
关键区别总结
语法 | 输入来源 | 变量替换 | 缩进处理 | 结束标记 | 典型场景 |
---|---|---|---|---|---|
<< |
多行文本 | ✅ 解析 | 敏感(需顶格) | 自定义(如 EOF) | 生成配置文件、多行输入 |
<<- |
多行文本 | ✅ 解析 | 忽略行首 Tab | 自定义(如 EOF) | 需要缩进的脚本(如 Makefile) |
<<< |
单行字符串 | ✅ 解析 | 不处理 | 无 | 快速传递变量或单行内容 |
使用场景建议
<<
:适合需要多行输入且需解析变量的场景(如生成配置文件)。<<-
:适合需要代码缩进的多行输入(如 Makefile 中的命令)。<<<
:适合快速传递变量或单行内容,避免创建子 Shell(如 grep
搜索变量内容)。通过合理选择语法,可以更高效地编写 Shell 脚本!
<<
、<<-
和 <<<
是三种不同的输入重定向操作符,分别用于处理多行输入、忽略缩进的多行输入和单行字符串输入。以下是它们的详细对比与使用场景: 1. <<
(Here Document)
功能:
EOF
)必须顶格书写,且前后一致。<< 'EOF'
)。语法:
command << delimiter
文档内容
delimiter
示例:
cat << EOF
Hello, World!
Today is $(date).
EOF
输出:
Hello, World!
Today is 2025-07-22 17:12:00
注意事项:
EOF
必须单独成行,且无前导空格或缩进。<< 'EOF'
禁用变量替换:cat << 'EOF'
Hello, $name!
EOF
2. <<-
(Here Document + 忽略缩进)
功能:
<<
类似,但允许在 每行前忽略前导 Tab
缩进。语法:
command <<- delimiter
文档内容(每行可包含前导 Tab)
delimiter
示例:
cat <<- EOF
This line has a leading Tab.
But the Tab is ignored.
EOF
输出:
This line has a leading Tab.
But the Tab is ignored.
注意事项:
Tab
,不忽略空格(避免混用空格和 Tab
)。EOF
必须顶格书写。 3. <<<
(Here String)
功能:
语法:
command <<< "字符串"
示例:
cat <<< "Hello, Here String!"
输出:
Hello, Here String!
注意事项:
name="Alice"
cat <<< "Hello, $name!"
输出:Hello, Alice!
4. 对比总结
操作符 | 输入类型 | 是否支持多行 | 是否忽略缩进 | 变量替换 | 典型用途 |
---|---|---|---|---|---|
<< |
Here Document | ✅ | ❌ | ✅(默认) | 多行输入、动态生成内容 |
<<- |
Here Document | ✅ | ✅(仅限 Tab ) |
✅(默认) | 脚本中对齐多行输入 |
<<< |
Here String | ❌ | ❌ | ✅(默认) | 快速传递单行字符串 |
5. 实际应用场景
5.1 动态生成多行配置文件
cat << EOF > config.txt
# Configuration File
username=admin
password=$PASS
EOF
5.2 远程执行脚本(避免变量提前解析)
ssh user@remote << 'EOF'
echo "Remote path: $PATH"
EOF
5.3 快速传递单行数据
wc -c <<< "This is a test string."
6. 常见错误及解决方案
6.1 分隔符未闭合
# 错误:缺少分隔符 EOF
cat << EOF
This is a line.
解决:确保分隔符 EOF
单独成行并正确闭合。
6.2 分隔符缩进问题
# 错误:分隔符 EOF 前有空格
cat << EOF
This line has leading spaces.
EOF
解决:分隔符必须顶格书写,或使用 <<- EOF
忽略 Tab
缩进。
6.3 混用空格和 Tab
# 错误:混用空格和 Tab 缩进
cat <<- EOF
This line uses spaces. # 不会被忽略
EOF
解决:<<-
仅忽略 Tab
,避免混用空格和 Tab
。
7. 总结
<<
:标准的 Here Document,适用于多行输入,需注意分隔符格式。<<-
:适合脚本中对齐多行输入,忽略每行前的 Tab
。<<<
:快速传递单行字符串,无需分隔符。根据需求选择合适的操作符,可以显著提升 Shell 脚本的可读性和效率。
<<
、<<-
和 <<<
是三种不同的输入重定向操作符,用于将文本内容传递给命令。它们的核心区别在于处理方式和应用场景。以下是详细对比: 1. <<
(Here Document,嵌入文档)
作用:将多行文本作为命令的输入,直到遇到结束分界符。
语法:
命令 << 分界符
多行文本内容...
分界符
特点:
\n
)默认不解析,需配合 echo -e
或 printf
。示例:
cat << EOF
Hello $USER # 变量被替换
Date: $(date +%F) # 命令被执行
Line 1\nLine 2 # \n 不被解释为换行
EOF
输出:
Hello root # 假设当前用户是root
Date: 2025-07-22
Line 1\nLine 2
2. <<-
(Here Document with Indentation,带缩进的嵌入文档)
作用:与 <<
类似,但允许结束分界符前带有 Tab缩进(空格无效),常用于脚本中保持代码整洁。
语法:
命令 <<- 分界符
多行文本内容...
分界符 # 可缩进(必须用Tab)
特点:
示例:
if true; then
cat <<-EOF
第一行文本(前面有Tab)
第二行文本(前面有Tab)
EOF # 结束符前的Tab会被忽略
fi
输出:
第一行文本(前面有Tab)
第二行文本(前面有Tab)
3. <<<
(Here String,嵌入字符串)
作用:将单个字符串作为命令的标准输入(stdin)。
语法:
命令 <<< "字符串内容"
特点:
示例:
# 等价于 echo "Hello world" | wc -c
wc -c <<< "Hello world" # 计算字符串长度(含换行符)
输出:
12 # "Hello world\n" 共12个字符
4. 关键区别总结
操作符 | 名称 | 输入形式 | 分界符要求 | 变量替换 | 缩进处理 |
---|---|---|---|---|---|
<< |
Here Document | 多行文本 | 分界符必须顶格 | ✅ | 无特殊处理 |
<<- |
带缩进的Here Document | 多行文本 | 分界符可Tab缩进 | ✅ | 内容中Tab保留,结束符Tab忽略 |
<<< |
Here String | 单个字符串(单行) | 无分界符,直接跟字符串 | ✅ | 无(视为单行文本) |
5. 常见应用场景
<<
的场景
cat << EOF > /etc/nginx/conf.d/site.conf
server {
listen 80;
server_name example.com;
}
EOF
<<-
的场景
function generate_script() {
cat <<-EOF
#!/bin/bash
echo "这是一个生成的脚本"
EOF
}
<<<
的场景
# 将字符串传递给grep
grep "world" <<< "Hello world" # 输出: Hello world
# 传递变量给命令
message="Hello"
echo -e <<< "$message\nWorld" # 输出两行: Hello 和 World
总结
<<
:最常用,适合多行文本输入,需注意分界符位置。<<-
:适合脚本中保持缩进,结束分界符可Tab缩进。<<<
:适合单行字符串输入,语法更简洁。根据输入是多行还是单行、是否需要保留缩进以及是否需要变量替换来选择合适的操作符。
一句话记忆:
<<
=原始 here-doc;<<-
=允许前导 TAB 缩进的 here-doc;<<<
=一次性单行字符串(here-string)。
──────────────────
<< EOF
(here-document)EOF
为止。$var
、$(cmd)
、\n
等都会被展开/解释(除非定界符被引号包裹)。例:
cat << EOF
hello $USER
EOF
# 输出包含 4 个空格
──────────────────
2. <<- EOF
(带减号的 here-document)
<<
相同,但:例:
if true; then
cat <<- TAB
line1
line2
TAB
fi
# 输出:
# line1
# line2
# (左侧 TAB 被吃掉)
──────────────────
3. <<< "string"
(here-string)
echo -n "string" | cmd
的简写,但更高效(无子进程)。例:
grep foo <<< "$USER:$HOME"
# 等价于 echo "$USER:$HOME" | grep foo
──────────────────
快速对照表
符号 | 行数 | 缩进处理 | 典型场景 |
---|---|---|---|
<< |
多行 | 保留所有前导空白 | 需要多行且保持原始格式 |
<<- |
多行 | 去掉前导 TAB | 脚本里美观缩进 |
<<< |
单行 | 无(只有一行) | 快速传递单行字符串给命令 |
记住:
<<
或 <<-
<<-
<<<
Shell脚本中<<、<<-和<<<重定向符号的区别和用法
在Shell脚本中,输入重定向符号用于将数据传递给命令,而不是从文件或标准输入读取。符号<<
、<<-
和<<<
各有特定用途,主要涉及“Here Document”和“Here String”机制。下面我将逐步解释它们的区别、用法和实际示例,确保内容清晰可靠。参考了Linux shell标准文档和常见实践。
1. <<
(Here Document)
command << DELIMITER
文本内容...
DELIMITER
EOF
)是大小写敏感的。$VAR
)和命令替换(如$(date)
)会被执行。cat << EOF
Hello, $USER! # $USER会被替换为当前用户名
Today is $(date). # $(date)会被替换为当前日期
EOF
输出:Hello, alice!
Today is Mon Jul 1 12:00:00 UTC 2024.
Here Document 常用于生成配置文件或交互式脚本。 2. <<-
(Here Document with Stripping Leading Tabs)
<<
类似,但会自动去除文本块中每行的前导制表符(tabs)。这使得脚本代码更整洁,同时不影响输出内容。command <<- DELIMITER
文本内容(可缩进)...
DELIMITER
-
符号是必须的。cat <<- EOF
Hello, $USER!
Today is $(date).
EOF
输出(无缩进):Hello, alice!
Today is Mon Jul 1 12:00:00 UTC 2024.
这在编写可读性高的脚本时非常有用。 3. <<<
(Here String)
command <<< "字符串"
echo "string" | command
的管道方式,减少子进程开销。grep
直接搜索字符串:grep "hello" <<< "hello world" # 输出: hello
或使用变量:str="test"
wc -c <<< "$str" # 计算字符串长度(包括换行符),输出: 5(因为"test"加换行符共5字节)
Here String 适合快速测试或单行数据处理。总结区别
符号 | 用途 | 数据处理 | 适用场景 |
---|---|---|---|
<< |
Here Document | 多行文本,扩展变量 | 生成文件、多行输入(如SQL查询) |
<<- |
Here Document(去缩进) | 多行文本,去除前导制表符 | 美化脚本代码,保持输出整洁 |
<<< |
Here String | 单行字符串,扩展变量 | 快速传递字符串,避免管道开销 |
关键区别:
<<
和 <<-
处理多行文本,而 <<<
处理单行字符串。<<-
是 <<
的变体,专为去除制表符缩进而设计。<<
、<<-
和 <<<
是用于输入重定向和多行文本处理的操作符,其核心区别在于输入格式、缩进处理以及适用场景。以下是详细对比与示例:一、基本功能与语法
操作符 | 功能描述 | 语法示例 |
---|---|---|
<< |
Here Document,将多行文本作为命令输入,直到遇到结束标记(如 EOF ) |
command << EOF\n内容\nEOF |
<<- |
支持缩进的 Here Document,允许行首的制表符(Tab)被忽略 | command <<- EOF\n\t缩进内容\nEOF |
<<< |
Here String,将单行字符串直接作为命令输入 | command <<< "字符串" |
二、行为差异与适用场景
1. <<
(Here Document)
cat << EOF > config.txt
server {
listen 80;
host example.com
}
EOF
输出文件内容:server {
listen 80;
host example.com
}
2. <<-
(缩进 Here Document)
if [ true ]; then
cat <<- EOF
缩进内容(Tab开头)
EOF
fi
输出:缩进内容
3. <<<
(Here String)
$VAR
)。echo "Hello World" | grep "World" # 传统管道方式
grep "World" <<< "Hello World" # Here String 简化写法
输出:Hello World
三、核心区别总结
特性 | << |
<<- |
<<< |
---|---|---|---|
输入类型 | 多行文本 | 多行文本(支持缩进) | 单行字符串 |
缩进处理 | 不支持 | 支持(仅制表符) | 不适用 |
变量替换 | 默认启用 | 默认启用 | 默认启用 |
结束标记要求 | 必须顶格 | 结束标记可缩进(Tab) | 无结束标记 |
典型用途 | 配置文件、交互命令 | 缩进代码块 | 快速传递字符串 |
四、实战场景对比
场景 1:生成配置文件(多行内容)
# 使用 `<<`
cat << EOF > nginx.conf
server {
listen 80;
server_name localhost;
}
EOF
# 使用 `<<-`(缩进代码块)
cat <<- EOF > nginx.conf
server {
listen 80;
server_name localhost;
}
EOF
输出文件内容相同,但 <<-
允许代码缩进,提升可读性。
场景 2:单行字符串处理
# 使用 `<<<` 快速传递参数
wc -w <<< "This is a test string"
# 输出:5
# 等效的传统写法
echo "This is a test string" | wc -w
场景 3:自动化交互命令
# 使用 `<<` 向 FTP 服务器发送指令
ftp -n << EOF
open ftp.example.com
user admin password
get file.txt
bye
EOF
# 使用 `<<<` 传递密码(不推荐,存在安全风险)
ftp -n <<< "open ftp.example.com\nuser admin password\nget file.txt\nbye"
五、注意事项
引号控制变量替换:
<< 'EOF'
:禁用变量替换(原样输出)。<< "EOF"
:允许变量替换但需转义双引号。name="World"
cat << 'EOF' # 禁用替换
Hello $name
EOF
# 输出:Hello $name
缩进限制:
<<-
仅支持制表符(Tab)缩进,空格无效。性能影响:
六、总结
<<
:适合需要多行输入且保留原始格式的场景(如生成配置文件)。<<-
:适合脚本中需要缩进的多行代码块,提升可读性。<<<
:适合快速传递单行字符串,简化管道操作。通过合理选择操作符,可以显著提升 Shell 脚本的灵活性和可维护性。
<<
、<<-
和 <<<
均是输入重定向操作符,但用途和行为有本质区别。以下是对它们的详细对比: 1. <<
(标准 Here Document)
command << DELIMITER
多行内容...
DELIMITER
cat << EOF
This is indented text.
But the delimiter "EOF" must be unindented.
EOF
2. <<-
(缩进 Here Document)
<<
类似,但允许结束标记前包含行首制表符(Tab),从而支持代码格式化。command <<- DELIMITER
多行内容(可缩进,但只能用 Tab)...
DELIMITER # 此处必须用 Tab 缩进,不能用空格
cat <<- EOF
This line starts with a Tab.
EOF # 这一行用 Tab 缩进
实际输出:This line starts with a Tab.
3. <<<
(Here String)
command <<< "字符串"
\n
)。grep "foo" <<< "foo bar baz" # 搜索 "foo",直接匹配成功
对比表格
操作符 | 输入类型 | 缩进支持 | 结束标记要求 | 典型场景 |
---|---|---|---|---|
<< |
多行文本块 | ❌ | 严格独占一行 | 生成配置文件、长文本输入 |
<<- |
多行文本块 | ✔️(仅 Tab) | 允许行首 Tab 缩进 | 需代码美观的脚本内多行输入 |
<<< |
单行字符串 | ❌ | 无结束标记 | 快速传递短内容、变量值 |
使用建议
<<-
+ Tab 缩进,增强脚本可读性。<<<
简化输入,替代 echo "内容" | command
。<<-
是 Bash 扩展语法,若需跨 Shell 兼容,用 <<
。常见错误
<<-
中使用空格:cat <<- EOF
Text...
EOF # 错误!缩进必须是 Tab,不能是空格
<<<
中的多行内容:cat <<< "Line 1
Line 2" # 实际输出是单行 "Line 1\nLine 2"
掌握这些操作符的差异,可大幅提升脚本编写的效率和可维护性!
<< EOF
(Here-Document)详解多回答笔记250722tee x << EOF
和 cat > x << EOF
和 cat << EOF > x
对比 笔记250709tee x << EOF
和 tee > x << EOF
和 tee << EOF > x
和 cat > x << EOF
和 cat << EOF > x
对比 笔记250722<< EOF
与 << ‘EOF‘
与 << “EOF“
有无引号的区别多回答笔记250722<< EOF
与 << \EOF
与 << ‘EOF‘
与 << “EOF“
多讲解笔记250722<<
与 <<-
与 <<<
多解说笔记250722EOF
与 echo
与 printf
, 将文本输出到文件