sed 替换带 & 的文本后内容重复:替换侧的 & 会插入整个匹配
sed 替换 SAS 宏变量时,替换侧的 & 插入原匹配内容。转义字面 & 与搜索点,先比较输出,GNU 原地编辑保留可恢复备份。
批量修改 SAS 文件中的宏变量,将 user=&uid. 换成 user=&sysuserid.,结果新文本里混入原匹配内容,看起来像重复拼接。即使用单引号包住 sed 表达式,也不会关闭 sed 自己对 & 的解释。
下面是问题表达式的示例,它先输出结果,避免直接改动源文件:
sed 's/user=&uid./user=&sysuserid./g' example.sas
替换侧的未转义 & 表示这一次匹配到的全部文本。因此 user=&sysuserid. 会插入 user=、原匹配内容和 sysuserid.,并不是写入字面宏变量。
字面 & 与搜索侧的点分别处理
要替换准确的 user=&uid.,可以写为:
sed 's/user=&uid\./user=\&sysuserid./g' example.sas
example.sas 是输入文件名示例。这条命令打印转换结果,不会修改原文件。搜索侧的 \. 匹配字面点,替换侧的 \& 写出字面 &。两处反斜线解决的是不同规则。
搜索侧的 & 在这个普通匹配中不表示“整个匹配”,无需照替换侧一样处理。原表达式中的未转义点则是正则通配符,可能把 user=&uidX 也纳入匹配;即使某次样本没有这种内容,仍应按实际替换目标决定是否转义。
下面是预期转换的示例,不是运行记录:
输入:user=&uid.
输出:user=&sysuserid.
g 会替换每行中的全部匹配。如果只希望修改特定语句或每行第一次出现的位置,应收紧范围,不要因表达式语法正确就默认全局替换符合业务要求。
先看输出,批量修改时保留独立备份
先用小范围真实样本查看输出并比较改动,确认只改到预定宏变量。SAS 字符串、注释和其他语句中的同名文本是否应一起替换,需要由文件内容决定;sed 不会理解 SAS 语义。
若使用 GNU sed 原地编辑,先保留独立可恢复副本,确认没有其他进程同时写文件。下面只示意一个文件的备份后编辑形式:
sed -i.before-change 's/user=&uid\./user=\&sysuserid./g' example.sas
它会改写文件,并生成带 .before-change 后缀的备份;执行前确认该备份名没有需要保留的旧文件,避免覆盖旧备份。不同 sed 实现的 -i 语法存在差异,脚本应检查目标系统,不要把 GNU 命令无条件用于其他实现。
编辑后比较备份和新文件,检查目标文本、非目标行及程序的语法。需要回退时,先确认备份确实是本次修改前的版本,保存当前文件再按原路径恢复;不要反向替换所有 sysuserid,那可能连原来就合法的内容也改掉。
动态替换文本还需处理其他特殊字符
将变量拼进 sed 替换侧时,& 只是其中一项。反斜线和选作分隔符的字符也有意义,shell 的变量展开又增加一层解析。固定表达式上的 \& 不能充当任意输入的通用转义函数。
如果替换内容来自外部数据,应使用经过核对的转义方式或适合该格式的解析工具。此次修复的成功标准是转换结果与目标字符串一致,改动范围可核对,备份能对应原文件;命令没有报错并不能证明文本替换正确。


