Shell脚本技巧:去除文件中字符串两端空白

在 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	
  1. sed 逐行读取。
  2. 第一行 " Hello World ":
    • 匹配开头 " ",替换为空。
    • 匹配结尾 " ",替换为空。
    • 输出:Hello World。
  3. 第二行 " 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	
  1. 第一行 " Hello World ":
    • $1="Hello",$2="World"。
    • 重新构建:Hello World(两端空白被移除,中间多余空格压缩为一个)。
    • 输出:Hello World。
  2. 第二行 " 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	
  1. 第一行 " Hello World ":
    • ${line%%[![:space:]]*} 匹配 " ",移除后得 "Hello World "。
    • ${trimmed##*[![:space:]]} 匹配 " ",移除后得 "Hello World"。
    • 输出:Hello World。
  2. 第二行 " 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	
  1. 第一行 " Hello World ":
    • tr -s:" Hello World "。
    • sed:"Hello World"。
    • 输出:Hello World。
  2. 第二行 " Tab Test ":
    • tr -s:" Tab Test "。
    • sed:"Tab Test"。
    • 输出:Tab Test。

优点与适用场景

  • 优点:结合两工具优势,处理复杂空白情况。
  • 场景:需要同时压缩行内空白并去除两端空白。

总结与选择建议

方法 原理核心 优点 缺点 适用场景
sed 正则替换 灵活,支持多种空白 需熟悉正则 批量清理
awk 字段重新构建 简洁,效率高 行内空白压缩 简单文本处理
参数扩展+read 字符串模式匹配 无外部依赖 性能低,语法复杂 小文件或变量处理
tr+sed 压缩+正则替换 处理复杂空白 多步骤 行内+两端清理
  • 快速批量处理 :推荐 sed 或 awk。
  • 小文件或变量:使用参数扩展。
  • 复杂空白清理 :结合 tr 和 sed。
相关推荐
GeW23 分钟前
产业新优势基础软件的人才底盘,从Linux与数据库开始
linux·数据库
by2099934 分钟前
Linux GCC/G++ 编译与 Makefile 构建
linux·运维·服务器·经验分享
cq林志炫1 小时前
两个Linux服务器之间同步文件
linux·运维·服务器
无人生还别怕2 小时前
如何搭建k8s服务(containerd部署)
linux·云原生·容器·kubernetes·openanolisos
企鹅侠客3 小时前
Linux CPU 负载平均值(Load Average)详解:从原理到实践
linux·运维·服务器·服务器负载
易点云徐源3 小时前
HP 暗影精灵 PRO 16 安装双系统后,开机直接进入 Windows,按 F9 才能进入 Ubuntu:GRUB 菜单不显示的处理方法
linux·运维·ubuntu
第404号工位4 小时前
离职退电脑前别只点“清空回收站”!手把手教你彻底抹除凭证与数字痕迹
linux·python·架构
就像楞次定律4 小时前
【Linux 学习记之二】C++ 构建体系与底层链接机制的深度透视(1)
linux·后端
米优4 小时前
linux下获取崩溃程序的core文件
linux·运维·服务器
qeen874 小时前
【Linux】动静态库的制作使用及ELF文件的宏观理解
linux·运维·库