在 Bash 脚本开发或日常文本处理中,清理每行首尾的空白字符(空格、制表符、换行符等)是高频需求,这一操作类似 Python 的 strip() 方法。Bash 本身未内置直接的 strip 函数,但可通过 awk、sed 等经典文本处理工具,或 Bash 内置的参数扩展特性实现。
一、首选方案:awk 命令
awk 是面向行和字段的文本处理工具,其内置的字段拆分与行重构机制,让它成为清理首尾空白的最优选择——代码极简,执行效率高,还能顺带规整字段间的多余空白。
1. 核心代码示例
# 基础版:自动过滤空行(空行$1为空,$1=$1为假,不打印)
awk '$1=$1' input.txt > output.txt
# 增强版:保留空行(强制打印,避免空行丢失)
awk '{$1=$1; print}' input.txt > output.txt
2. 底层原理剖析
要理解该命令的核心,需先掌握 awk 处理行的底层逻辑:
- 字段拆分:
awk默认以「任意空白符(空格、制表符、换行符)」为分隔符,将每行拆分为$1(第一个字段)、$2(第二个字段)……$NF(最后一个字段),且拆分时会自动忽略行首/行尾的空白。例如行Hello World会被拆分为$1="Hello"、$2="World",而原始整行内容(含首尾空格)仍保留在$0中。 - 行重构触发:
$1=$1看似是“将$1赋值给自身”的无意义操作,但awk规定:修改任意字段($n)会触发整行($0)的重新拼接。拼接时,awk会用「输出字段分隔符(OFS,默认是单个空格)」连接所有字段,最终生成新的$0。 - 空白清理效果:重构后的
$0不再包含行首/行尾的空白(拆分时已忽略),且字段间的多个空白会被压缩为单个空格(OFS 特性)。 - 打印逻辑:
awk遵循“模式-动作”语法,$1=$1作为模式,结果为真时执行默认动作print $0;增强版{print}则强制打印,避免空行因$1=$1为假而丢失。
3. 执行过程演示
假设 input.txt 内容如下(含行首/尾空格、制表符,字段间多空格):
Hello World
Tab Test
(空行)
执行 awk '{$1=$1; print}' input.txt 后:
- 第一行
Hello World:拆分得到$1=Hello、$2=World,重构后$0=Hello World,输出Hello World; - 第二行
Tab Test:拆分得到$1=Tab、$2=Test,重构后$0=Tab Test,输出Tab Test; - 空行:
$1为空,但{print}强制打印,保留空行。
最终 output.txt 内容:
Hello World
Tab Test
二、灵活方案:sed 命令
sed(流编辑器)通过正则表达式匹配并替换文本,适合对空白清理规则有精准控制的场景(比如仅清理空格、保留制表符,或仅清理行首不清理行尾)。
1. 核心代码示例
# 通用版:清理行首/尾所有空白字符(空格、制表符等)
sed 's/^[[:space:]]*\|[[:space:]]*$//g' input.txt > output.txt
# 简化版(GNU sed 兼容):用 -E 启用扩展正则,语法更简洁
sed -E 's/^[[:space:]]+|[[:space:]]+$//g' input.txt > output.txt
# 定制版:仅清理行首/尾空格(不处理制表符)
sed 's/^ *\| *$//g' input.txt > output.txt
2. 底层原理剖析
sed 逐行读取文本,对每行执行指定的正则替换命令,核心参数解析:
s/pattern/replacement/g:全局替换命令,s表示“替换”,g表示“全局匹配(一行内所有符合条件的内容)”;^[[:space:]]*:匹配行首的空白字符:^锚定行首,[[:space:]]是 POSIX 标准字符类(匹配所有空白,跨平台兼容),*匹配零个或多个(+匹配一个或多个,更精准);\|(基础版)/|(扩展版):正则“或”操作符,连接“行首空白”和“行尾空白”两个匹配模式;[[:space:]]*$:匹配行尾的空白字符,$锚定行尾;//:将匹配到的空白字符替换为空字符串,实现“删除”效果。
3. 执行过程演示
仍以包含首尾空白的 input.txt 为例:
Hello World
Tab Test
执行 sed -E 's/^[[:space:]]+|[[:space:]]+$//g' input.txt 后:
- 第一行
Hello World:匹配行首的和行尾的,均替换为空,输出Hello World; - 第二行
Tab Test:匹配行首的制表符和行尾的,均替换为空,输出Tab Test。
三、进阶方案:Bash 内置参数扩展
若场景限制无法使用 awk/sed(如极简环境),可通过 Bash 内置的参数扩展实现单行空白清理,无需调用外部工具。
1. 核心代码示例
# 逐行读取文件,清理每行首尾空白
while IFS= read -r line; do
# 清理行首空白:移除开头所有空白字符
line_ltrim="${line##+([[:space:]])}"
# 清理行尾空白:移除结尾所有空白字符
line_strip="${line_ltrim%%+([[:space:]])}"
# 输出处理后的行
echo "$line_strip"
done < input.txt > output.txt
2. 底层原理剖析
Bash 参数扩展通过通配符匹配实现字符串截取,核心语法:
${var##pattern}:从变量开头删除最长匹配pattern的内容,+([[:space:]])匹配一个或多个空白字符(需开启extglob扩展,默认已开启);${var%%pattern}:从变量结尾删除最长匹配pattern的内容;IFS= read -r line:IFS=避免read命令自动忽略行首空白,-r保留反斜杠等特殊字符,保证读取原始行内容。
3. 注意事项
该方案纯 Bash 实现,但需逐行循环处理,大文件场景下效率低于 awk/sed,适合小文件或嵌入式 Bash 环境。
四、方案对比与选型建议
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| awk | 代码极简、执行高效、自动规整字段间空白 | 无法单独保留行首/尾某一侧空白 | 通用场景(推荐首选) |
| sed | 正则灵活、可精准定制清理规则 | 语法稍复杂,大文件效率略低于 awk | 需精准控制清理范围(如仅清空格) |
| Bash 内置 | 无外部工具依赖、环境兼容性极强 | 逐行循环效率低,代码量大 | 极简环境、小文件处理 |
五、总结
清理行首尾空白是 Bash 文本处理的基础操作,其中 awk '$1=$1' 是兼顾简洁与效率的最优解,适合绝大多数场景;sed 适合需要精准控制正则匹配的定制化场景;Bash 内置参数扩展则是无外部工具依赖时的兜底方案。掌握这三种方法,可覆盖从日常脚本到特殊环境的所有空白清理需求。
原文 https://blog.csdn.net/2301_79518550/article/details/146964991