仅替换字符串搜索中的某些匹配项

仅替换字符串搜索中的某些匹配项

继续回答我之前的问题:搜索和替换多个文件(包括子目录)我希望进行一些调整,以免使 CFML 无效。基本上,我试图避免嵌套<cfoutput></cfoutput>

命令:

sed -i -re 's/\<\/form\>/\<input type="hidden" name="_token" value="\<cfoutput\>#STOKEN#\<\/cfoutput\>"\>\<\/form\>/gi' ./math.cfm

变化:

</form>

到:

<input type="hidden" name="_token" value="<cfoutput>#STOKEN#</cfoutput>"/>
</form>

我该如何更改命令才能实现以下目标?

  1. 如果</form>包含在内<cfoutput>....</cfoutput>,则只需插入<input type="hidden" name="_token" value="#STOKEN#"/>

因此

<cfoutput>
    ....
    </form>
    ....
</cfoutput>

应该变成:

<cfoutput>
    ....
    <input type="hidden" name="_token" value="#STOKEN#"/>
    </form>
    ....
</cfoutput>
  1. 但是,如果</form>尚未包含在内,<cfoutput>....</cfoutput>则插入<input type="hidden" name="_token" value="<cfoutput>#STOKEN#</cfoutput>"/>

因此

....
</form>

应该变成:

....
<input type="hidden" name="_token" value="<cfoutput>#STOKEN#</cfoutput>"/>
</form>

答案1

免责声明:这假设没有标签与或标签</form>放在同一行,从示例中看似乎是这种情况;如果不是这种情况,则可能会出现错误行为,并使用错误的字符串替换同一行上后面的标签之前的标签和同一行上前面的标签之后的标签。因此,如果您的使用情况比示例中实际看起来更复杂(即,您的标签与或标签放在同一行),您最好查看 HTML 解析器。否则这将正常工作。<cfoutput></cfoutput></form><cfoutput></form></cfoutput></form><cfoutput></cfoutput>

使用awk

awk '/<cfoutput>/,/<\/cfoutput>/ {sub(/<\/form>/, "<input type=\"hidden\" name=\"_token\" value=\"#STOKEN#\"/>", $0); print; next} {sub(/<\/form>/, "<input type=\"hidden\" name=\"_token\" value=\"<cfoutput>#STOKEN#</cfoutput>\"/>", $0); print}' infile

awk脚本扩展:

/<cfoutput>/,/<\/cfoutput>/ {
    sub(/<\/form>/, "<input type=\"hidden\" name=\"_token\" value=\"#STOKEN#\"/>", $0);
    print;
    next
}
{
    sub(/<\/form>/, "<input type=\"hidden\" name=\"_token\" value=\"<cfoutput>#STOKEN#</cfoutput>\"/>", $0);
    print
}
  • /<cfoutput>/,/<\/cfoutput>/:仅当当前记录位于包含字符串的记录与包含字符串<cfoutput>的记录之间时,才执行以下(复合)语句;</cfoutput>
  • sub(/<\/form>/, "<input type=\"hidden\" name=\"_token\" value=\"#STOKEN#\"/>", $0);</form>: 将当前记录中的每个出现的 替换为<input type="hidden" name="_token" value="#STOKEN#"/>
  • print:打印当前记录
  • next:跳至下一条记录
  • sub(/<\/form>/, "<input type=\"hidden\" name=\"_token\" value=\"<cfoutput>#STOKEN#</cfoutput>\"/>", $0);</form>: 将当前记录中的每个出现的 替换为<input type="hidden" name="_token" value="<cfoutput>#STOKEN#</cfoutput>"/>
  • print:打印当前记录
user@debian ~ % cat infile
<html>

<!-- stuff -->

</form>
<cfoutput>
    </form>
</cfoutput>

<!-- stuff -->

</html>
user@debian ~ % awk '/<cfoutput>/,/<\/cfoutput>/ {sub(/<\/form>/, "<input type=\"hidden\" name=\"_token\" value=\"#STOKEN#\"/>", $0); print; next} {sub(/<\/form>/, "<input type=\"hidden\" name=\"_token\" value=\"<cfoutput>#STOKEN#</cfoutput>\"/>", $0); print}' infile
<html>

<!-- stuff -->

<input type="hidden" name="_token" value="<cfoutput>#STOKEN#</cfoutput>"/>
<cfoutput>
    <input type="hidden" name="_token" value="#STOKEN#"/>
</cfoutput>

<!-- stuff -->

</html>

相关内容