如何避免Shell脚本Sed修改密码变量内容

时间:2015-02-20 06:45:35

标签: regex bash shell awk sed

当我尝试按照以下方式进行检查时

sed -e 's,</Context>,<Resource name="ABC"  password="'"$DB_PASS"'"/>\n&,' -i /path

sed正在截断反斜杠。

例如

DB_PASS='1!2@3#4$5%6^7&8*9(0)[{]}\|'

O / p是

<Resource name="jdbc/KARDB" 
 password=""1!2@3#4$5%6^7</Context>8*9(0)[{]}|""/> </Context>

如果我的DB_PASS包含反斜杠,&amp ;,单引号双引号,我不希望sed更改密码内容。但要原样替换。

谢谢, 库苏马

1 个答案:

答案 0 :(得分:0)

您遇到的具体问题是您的密码包含&s命令的替换部分中的密码是指匹配的文本。

由于已成为我的一部分,因此将shell变量精确地替换为sed代码通常不是一个好主意,原因如下:sed无法区分代码和数据。这是可能出错的更无害的事情之一;想象一下如果某人输入了rm -Rf /,e #这样的密码,GNU会怎么做。

使用GNU awk直接替换(因为RT是GNU特定的,所以必须是gawk)

DB_PASS="$DB_PASS" gawk -v RS='</Context>' '{ printf $0; if(RT == RS) { print "<Resource name=\"jdbc/KARDB\" password=\"" ENVIRON["DB_PASS"] "\"/>" } printf RT }'

通常的-v dbpass="$DB_PASS"技巧在这里不起作用,因为您甚至不希望解释转义序列,因此我们强制将DB_PASS添加到awk的环境并从那里获取。如果您希望文件在适当位置更改并且您具有GNU awk 4.1.0或更高版本,请将-i inplace添加到a​​wk的选项中,但我通常会使用cp file file~; awk ... file~ > file进行备份,以防出现问题。< / p>

但是有一个问题:你如何处理密码中的"?做dbpass = ENVIRON["DB_PASS"]; gsub(/"/, "&quot;", dbpass);之类的事情并在输出中使用dbpass可能是个好主意。对于所有其他关键字符也是如此,例如<>

由于您似乎正在解析XML数据,因此最好使用基于XML的工具,这样当Context标记为空并写为{{1}时,您不会遇到问题并避免上述问题(可能是一个相当大的问题)。例如,使用xmlstarlet,您可以执行以下操作:

<Context/>

这包括三个步骤:

xmlstarlet ed -s '//Context' -t elem -n Resource -i '//Context/Resource[not(@name)]' -t attr -n name -v 'jdbc/KARDB' -i '//Context/Resource[@name="jdbc/KARDB"]' -t attr -n password -v "$DB_PASS"

在每个-s '//Context' -t elem -n Resource 节点下插入一个空的Resource子节点(如果只有一个节点,则可以这样做;否则您可能希望更详细地指定它)

Context

在每个没有名称的-i '//Context/Resource[not(@name)]' -t attr -n name -v 'jdbc/KARDB' 节点中插入一个属性name="jdbc/KARDB"(希望只有我们刚刚插入的那个),并且

Context/Resource

-i '//Context/Resource[@name="jdbc/KARDB"]' -t attr -n password -v "$DB_PASS" 属性password节点下的每个$DB_PASS节点中插入值Resource(正确引用)的Context属性name(同样,这应该只是我们刚插入的节点)。对于一次性插入整个节点的更完美的解决方案,您需要仔细研究xslt,但如果您对原始的sed方法感到满意,那么这种方法的缺点都不应该是一个问题。 / p>