在 Bash 脚本中,处理文件时经常需要清理每行两端的空白字符(包括空格、制表符、换行符等),类似于 Python 的 strip() 方法。虽然 Bash 没有直接内置函数实现这一功能,但可以通过内置功能和外部工具(如 sed、awk、参数扩展等)实现。本文将详细介绍几种常用方法,深入剖析其工作原理,并提供代码示例。
方法 1:使用 sed 命令
代码示例
bash
sed 's/^[[:space:]]*\|[[:space:]]*$//g' input.txt > output.txt
原理
sed:流编辑器(Stream Editor),逐行读取文件并应用指定的编辑命令。s/pattern/replacement/g:替换命令,s表示替换,pattern是要匹配的内容,replacement是替换结果(这里为空),g表示全局替换。^[[:space:]]*:^:匹配行首。[[:space:]]:POSIX 字符类,匹配所有空白字符(空格、制表符、换行符等)。*:表示零个或多个匹配,匹配行首的所有连续空白字符。
\|:正则表达式中的"或"操作符,连接两个模式。[[:space:]]*$:$:匹配行尾。[[:space:]]*:匹配行尾的所有连续空白字符。
//:将匹配的空白替换为空字符串。> output.txt:将处理结果重定向到新文件。
执行过程
假设 input.txt 内容为:
Hello World
Tab Test
sed逐行读取。- 第一行
" Hello World ":- 匹配开头
" ",替换为空。 - 匹配结尾
" ",替换为空。 - 输出:
Hello World。
- 匹配开头
- 第二行
" Tab Test ":- 匹配开头
" "(制表符),替换为空。 - 匹配结尾
" ",替换为空。 - 输出:
Tab Test。
- 匹配开头
优点与适用场景
- 优点:支持正则表达式,处理多种空白字符,适合批量文件操作。
- 场景:清理日志文件或格式化文本数据。
方法 2:使用 awk 命令(王炸)
代码示例
bash
awk '{$1=$1};1' input.txt > output.txt
原理
awk:文本处理工具,按行处理文件,默认以空白字符(空格、制表符等)作为字段分隔符。{$1=$1}:$1:表示当前行的第一个字段。=$1:将第一个字段重新赋值给自身。- 关键机制 :
awk在重新赋值时,会重新构建整行,自动去除行首和行尾的空白字符,同时将字段间的多个空白压缩为单个空格。
1:- 在
awk中,条件为真(非零)时打印整行。 - 这里
1恒为真,等价于{print $0},输出处理后的行。
- 在
> output.txt:将结果重定向到新文件。
执行过程
假设 input.txt 内容为:
Hello World
Tab Test
- 第一行
" Hello World ":$1="Hello",$2="World"。- 重新构建:
Hello World(两端空白被移除,中间多余空格压缩为一个)。 - 输出:
Hello World。
- 第二行
" Tab Test ":$1="Tab",$2="Test"。- 重新构建:
Tab Test。 - 输出:
Tab Test。
优点与适用场景
- 优点:代码简洁,自动处理所有空白字符,效率高。
- 场景:快速清理简单文本文件,尤其是字段分隔明确的内容。
注意
- 如果行中只有空白字符,输出为空行。
方法 3:使用 Bash 参数扩展与 while read
代码示例
bash
while read -r line; do
trimmed="${line#"${line%%[![:space:]]*}"}"
trimmed="${trimmed%"${trimmed##*[![:space:]]}"}"
echo "$trimmed"
done < input.txt > output.txt
原理
while read -r line:read -r:逐行读取文件内容,-r防止反斜杠转义。< input.txt:将文件内容重定向到循环。
"${line#"${line%%[![:space:]]*}"}":${line%%[![:space:]]*}:从$line末尾开始,匹配最短的非空白字符之前的部分(即开头的所有空白)。${line#...}:从$line开头移除匹配的部分。- 结果:去掉行首空白。
"${trimmed%"${trimmed##*[![:space:]]}"}":${trimmed##*[![:space:]]}:从$trimmed开头开始,匹配最长的非空白字符之后的部分(即结尾的所有空白)。${trimmed%...}:从$trimmed结尾移除匹配的部分。- 结果:去掉行尾空白。
echo "$trimmed":输出处理后的行。> output.txt:将结果重定向到新文件。
执行过程
假设 input.txt 内容为:
Hello World
Tab Test
- 第一行
" Hello World ":${line%%[![:space:]]*}匹配" ",移除后得"Hello World "。${trimmed##*[![:space:]]}匹配" ",移除后得"Hello World"。- 输出:
Hello World。
- 第二行
" Tab Test ":${line%%[![:space:]]*}匹配" ",移除后得"Tab Test "。${trimmed##*[![:space:]]}匹配" ",移除后得"Tab Test"。- 输出:
Tab Test。
优点与适用场景
- 优点:无需外部工具,纯 Bash 实现,适合变量处理或小文件。
- 场景:需要逐行处理并结合其他逻辑时。
注意
- 对大文件性能较低,因逐行读取和处理较慢。
方法 4:使用 tr 和 sed 组合
代码示例
bash
tr -s '[:space:]' < input.txt | sed 's/^[[:space:]]*\|[[:space:]]*$//g' > output.txt
原理
tr -s '[:space:]':-s:压缩(squeeze),将连续的空白字符替换为单个空白。'[:space:]':匹配所有空白字符。- 作用:将行内多余空白压缩,但无法直接去除两端空白。
sed 's/^[[:space:]]*\|[[:space:]]*$//g':- 与方法 1 相同,去除行首和行尾的空白。
- 管道 :
tr处理后输出到sed,再重定向到文件。
执行过程
假设 input.txt 内容为:
Hello World
Tab Test
- 第一行
" Hello World ":tr -s:" Hello World "。sed:"Hello World"。- 输出:
Hello World。
- 第二行
" Tab Test ":tr -s:" Tab Test "。sed:"Tab Test"。- 输出:
Tab Test。
优点与适用场景
- 优点:结合两工具优势,处理复杂空白情况。
- 场景:需要同时压缩行内空白并去除两端空白。
总结与选择建议
| 方法 | 原理核心 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
sed |
正则替换 | 灵活,支持多种空白 | 需熟悉正则 | 批量清理 |
awk |
字段重新构建 | 简洁,效率高 | 行内空白压缩 | 简单文本处理 |
参数扩展+read |
字符串模式匹配 | 无外部依赖 | 性能低,语法复杂 | 小文件或变量处理 |
tr+sed |
压缩+正则替换 | 处理复杂空白 | 多步骤 | 行内+两端清理 |
- 快速批量处理 :推荐
sed或awk。 - 小文件或变量:使用参数扩展。
- 复杂空白清理 :结合
tr和sed。