如何解决SED处理文本后末尾换行符丢失导致内容粘连的问题?
我的问题场景
最近在用sed处理一批文本文件,主要是把文件里的YYMMDD、MMDD这类日期占位符替换成当前实际日期,然后把处理后的内容追加到同一个目标文件里。结果发现一个坑:每个源文件的最后一行都没有换行符,导致拼接后上一个文件的末尾直接跟下一个文件的开头粘在了一起,完全打乱了格式。
举个实际例子:
- 文件1内容:
00 YYMMDD TEST 05 3452256 MMDD 33456 80 File Trailer(最后一行没有换行) - 文件2内容:
00 YYMMDD TEST 05 445674 MMDD 234456 80 File Trailer(最后一行也没有换行)
本来期望处理后是两行独立的内容,结果实际变成了:00 YYMMDD TEST 05 3452256 MMDD 33456 80 File Trailer00 YYMMDD TEST 05 445674 MMDD 234456 80 File Trailer
我用的脚本代码是这样的:
YYYY=$(date +"%Y") YY=$(date +"%y") MM=$(date +"%m") DD=$(date +"%d") HH=$(date +"%H") MI=$(date +"%M") SS=$(date +"%S") JJJ=$(date +"%j") sed -- "s/yyyymmdd/$yyyyMMdd/g;s/yymmdd/$yyMMdd/g;s/mmdd/$mmdd/g;s/yyjjj/$yyjjj/g" "$full_path" >> $deploy_path
排查了半天,确认sed的替换逻辑没问题,问题根源就是源文件的最后一行缺少换行符(LF/CRLF),导致追加时没有分隔。
有效的解决方法
针对这个问题,我整理了两种靠谱的解决思路,都是围绕着给缺失换行的文件补全换行来做的:
方法1:用cat先补换行再交给sed处理
cat命令有个特性:如果读取的文件最后一行没有换行,它会自动补上一个。所以我们可以先通过cat读取源文件,再把内容管道给sed处理,这样就保证了输出的内容一定有尾行换行:
YYYY=$(date +"%Y") YY=$(date +"%y") MM=$(date +"%m") DD=$(date +"%d") HH=$(date +"%H") MI=$(date +"%M") SS=$(date +"%S") JJJ=$(date +"%j") # 用cat补全换行,再传给sed做替换 cat "$full_path" | sed -- "s/yyyymmdd/$YYYY$MM$DD/g;s/yymmdd/$YY$MM$DD/g;s/mmdd/$MM$DD/g;s/yyjjj/$YY$JJJ/g" >> $deploy_path
这里顺便提一句:我发现原脚本里变量大小写不匹配(比如定义了YYYY,但替换时用了$yyyyMMdd),这会导致变量无法正确解析,一定要保持变量大小写一致!
方法2:处理完文件后强制追加一个换行
如果不想用cat,也可以在每个文件处理完成后,手动给目标文件追加一个换行符:
YYYY=$(date +"%Y") YY=$(date +"%y") MM=$(date +"%m") DD=$(date +"%d") HH=$(date +"%H") MI=$(date +"%M") SS=$(date +"%S") JJJ=$(date +"%j") # 先处理文件内容 sed -- "s/yyyymmdd/$YYYY$MM$DD/g;s/yymmdd/$YY$MM$DD/g;s/mmdd/$MM$DD/g;s/yyjjj/$YY$JJJ/g" "$full_path" >> $deploy_path # 追加换行符 echo "" >> $deploy_path
不过这个方法有个小缺点:如果某个源文件本身已经有尾行换行,就会多出来一个空行。所以更推荐方法1,它只会在确实缺少换行的时候才补加。
额外优化:简化日期变量的定义
其实可以直接把要替换的日期格式提前拼接好,这样sed命令会更简洁,也不容易出错:
# 直接生成需要的日期格式字符串 yyyyMMdd=$(date +"%Y%m%d") yyMMdd=$(date +"%y%m%d") mmdd=$(date +"%m%d") yyjjj=$(date +"%y%j") # 直接用预定义好的变量替换 sed -- "s/yyyymmdd/$yyyyMMdd/g;s/yymmdd/$yyMMdd/g;s/mmdd/$mmdd/g;s/yyjjj/$yyjjj/g" "$full_path" >> $deploy_path
这样不仅代码可读性更高,还避免了变量拼接时的大小写失误。
内容的提问来源于stack exchange,提问作者theObserver

