如何防止sed修改文件时将原有CRLF换行符变更为LF格式
我正在通过.sh脚本修改.js文件内容,但出现了非预期的副作用。
使用的.sh文件代码如下:
# update file version="0.1" file="Test.js" updated_line="const version = \"$version\";" sed -i "1s/.*/$updated_line/" $file
Test.js原始文件内容如下:
const version = "0"; const moreVars = {};
运行该.sh脚本后,文件内容更新成功,但IDE发出提示,文件换行符已从CRLF变为LF:
核心诉求:在使用sed完成文件内容修改的同时,保留文件原有的换行符格式不变。
默认情况下,GNU sed会按Unix文本流规则处理文件:逐行读取内容时会自动剥离行尾的\r(CR字符),输出时仅使用\n(LF字符)作为换行符,因此原本Windows格式的CRLF(\r\n)换行,经过sed处理后会全部变成LF格式换行。
方案1:调整sed匹配规则,捕获并保留行尾的CR字符
修改sed的替换匹配逻辑,不要直接替换整行所有内容,而是捕获行尾可能存在的\r字符,替换时将其拼接到新行末尾,兼容CRLF和LF两种换行格式。修改后的脚本代码:# update file version="0.1" file="Test.js" updated_line="const version = \"$version\";" # 捕获行尾可选的\r字符,替换时原样保留 sed -i "1s/^.*\(\r\?\)$/$updated_line\1/" $file该写法不需要依赖sed的特殊参数,跨环境兼容性更好:原文件是CRLF格式时会保留
\r,原文件是LF格式时也不会额外添加多余字符。方案2:开启sed的二进制处理模式
主流发行版的GNU sed、Git Bash环境自带的sed都支持-b(二进制)参数,开启后sed不会对换行符做自动转换,直接按字节流处理文件,不会修改原有换行格式。命令写法:sed -i -b "1s/.*/$updated_line/" $file方案3:处理后按原格式转换(兜底方案,不推荐)
可以先通过file命令检测原文件的换行格式,sed处理完成后,使用unix2dos/dos2unix命令把文件转换回原换行格式。该方案需要额外执行检测和转换命令,IO开销更高,仅作为前两种方案不可用时的备选。
内容的提问来源于stack exchange,提问作者Cold_Class

