使用sed结合CSV批量修改XML文件名及内容的同值匹配问题
问题描述
需要编写Bash脚本,通过sed批量修改500多个文件夹中的XML文件名及其内容,不安装xmlstarlet。现有脚本基于逗号分隔的customerlogin.csv(含oldStr、midStr、newStr三列)处理:当三列值都不同时脚本正常工作,但当oldStr与midStr值相同时,XML文件名能成功修改,可文件内的对应字符串却未替换。
示例数据
原文件路径:
/var/opt/FTPserver/users/MainUsers/junk/VFS/junk2.xml原文件内容:
<url>file://home/FTPserver/Customer/junk2/</url>期望修改后路径:
/var/opt/FTPserver/users/MainUsers/junk/VFS/treasure.xml期望修改后内容:
<url>file://home/FTPserver/Customer/treasure/</url>CSV示例:
junk,junk2,treasure help,helpful,helping old,middle,new dog,dog,cat
现有脚本
dir='/var/opt/FTPserver/users/MainUsers/' while IFS=, read -r oldStr midStr newStr; do oldFile="$dir/$oldStr/VFS/${midStr}.xml" newFile="$dir/$oldStr/VFS/${newStr}.xml" if [[ -f "$oldFile" ]] && [[ ! -f "$newFile" ]]; then sed "s:/$midStr/:/$newStr/:" "$oldFile" > "$newFile" && rm -f "$oldFile" fi done < customerlogin.csv
异常现象
当oldStr和midStr同为dog时,文件名成功改为cat.xml,但文件内容仍为<url>file://home/FTPserver/Customer/dog</url>,未替换为期望的<url>file://home/FTPserver/Customer/treasure/</url>。
问题原因
现有sed命令仅匹配带斜杠的路径片段/$midStr/,但当oldStr与midStr相同时,XML内容中的路径片段是/$midStr(末尾无斜杠,直接跟</url>标签),导致正则表达式无法命中,因此内容替换失败。
解决办法
修改sed的正则表达式,使其同时匹配带斜杠和**不带斜杠(后跟标签闭合符>)**的两种情况,同时添加全局替换标志g确保所有匹配项都被替换:
dir='/var/opt/FTPserver/users/MainUsers/' while IFS=, read -r oldStr midStr newStr; do oldFile="$dir/$oldStr/VFS/${midStr}.xml" newFile="$dir/$oldStr/VFS/${newStr}.xml" if [[ -f "$oldFile" ]] && [[ ! -f "$newFile" ]]; then # 使用扩展正则匹配两种路径格式,全局替换 sed -E "s:/$midStr(/|>):/$newStr/:g" "$oldFile" > "$newFile" && rm -f "$oldFile" fi done < customerlogin.csv
说明
-E参数启用扩展正则表达式,简化分组语法/|>表示匹配$midStr后跟随斜杠/或标签闭合符>g标志确保文件内所有符合条件的匹配项都被替换,避免遗漏
内容的提问来源于stack exchange,提问作者Trevor McDaniel

