简体   繁体   English

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

[英]How to avoid Shell script Sed modifying password variable contents

When i am trying to sed as below 当我想尝试下面的sed

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

sed is truncating backslash. sed正在截断反斜杠。

For example 例如

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

O/p is O / p是

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

if my DB_PASS contains backslash, &, single quote double quote anyother spl characters i dont want sed to change password contents. 如果我的DB_PASS包含反斜杠,&,单引号双引号任何其他spl字符我不希望sed更改密码内容。 but substitute as it is. 但要原样替换。

Thanks, Kusuma 谢谢,Kusuma

The specific problem you run into is that your password contains & , which in the replacement part of an s command refers to the matched text. 您遇到的具体问题是您的密码包含& ,在s命令的替换部分中引用匹配的文本。

As has become a litany of mine, it is generally not a good idea to substitute shell variables into sed code precisely for reasons like these: sed cannot differentiate between code and your data. 由于以下原因将shell变量精确地替换为sed代码通常不是一个好主意:sed无法区分代码和数据。 This is one of the more harmless things that could go wrong; 这是可能出错的更无害的事情之一; imagine what GNU sed would have done if someone had entered a password like rm -Rf /,e # . 想象一下如果有人输入了像rm -Rf /,e #这样的密码,GNU会怎么做。

A direct replacement with GNU awk (it has to be gawk because RT is GNU-specific) could be 用GNU awk直接替换(它必须是gawk,因为RT是GNU特定的)可能是

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

The usual -v dbpass="$DB_PASS" trick does not work here because you don't even want escape sequences interpreted, so we forcefully add DB_PASS to awk 's environment and take it from there. 通常的-v dbpass="$DB_PASS"技巧在这里不起作用,因为你甚至不想解释转义序列,所以我们强行将DB_PASS添加到awk的环境中并从那里获取它。 Add -i inplace to awk's options if you want the file to be changed in place and you have GNU awk 4.1.0 or later, although I usually use cp file file~; awk ... file~ > file 如果你想要在适当的位置更改文件并且你有GNU awk 4.1.0或更高版本,尽管我通常使用cp file file~; awk ... file~ > file添加-i inplace到awk的选项中cp file file~; awk ... file~ > file cp file file~; awk ... file~ > file to have a backup in case things go wrong. cp file file~; awk ... file~ > file以便在出现问题时进行备份。

There's a problem, however: how do you handle " in passwords? Might be a good idea to do something like dbpass = ENVIRON["DB_PASS"]; gsub(/"/, "&quot;", dbpass); 但是有一个问题:你如何处理"密码?可能做一些像dbpass = ENVIRON["DB_PASS"]; gsub(/"/, "&quot;", dbpass); and use dbpass in the output. 并在输出中使用dbpass And the same for all other critical characters, such as < and > . 对于所有其他关键字符也是如此,例如<>

Since you appear to be parsing XML data, it would be better to use an XML-based tool, so that you don't run into problems when the Context tag is empty and written as <Context/> , and to avoid the above problem (which could be a rather big one). 由于您似乎正在解析XML数据,因此最好使用基于XML的工具,以便在Context标记为空并写为<Context/>时不会遇到问题,并避免上述问题(这可能是一个相当大的)。 For example, with xmlstarlet you could do something like this: 例如,使用xmlstarlet,您可以执行以下操作:

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"

This consists of three steps: 这包括三个步骤:

-s '//Context' -t elem -n Resource

inserts an empty Resource subnode under every Context node (this is fine if there's only one; otherwise you might want to specify it in more detail) 在每个Context节点下插入一个空的Resource子节点(如果只有一个,那就没问题;否则你可能想要更详细地指定它)

-i '//Context/Resource[not(@name)]' -t attr -n name -v 'jdbc/KARDB'

inserts an attribute name="jdbc/KARDB" in every Context/Resource node that has no name (which is hopefully only the one we just inserted), and 在每个没有名称的Context/Resource节点中插入一个属性name="jdbc/KARDB" (希望只有我们刚插入的那个),以及

-i '//Context/Resource[@name="jdbc/KARDB"]' -t attr -n password -v "$DB_PASS"

inserts a password attribute with the value of $DB_PASS (properly quoted) in every Resource node under a Context node whose name attribute has the value jdbc/KARDB (again, this should be only the node we just inserted). name属性值为jdbc/KARDBContext节点下的每个Resource节点中插入值为$DB_PASS (正确引用)的password属性(同样,这应该只是我们刚刚插入的节点)。 For a more perfect solution that inserts the whole node in one go, you'll want to take a closer look at xslt, but if you were happy with the original sed approach, none of the shortcomings of this approach should be a problem. 对于一次性插入整个节点的更完美的解决方案,您需要仔细研究xslt,但如果您对原始的sed方法感到满意,那么这种方法的缺点都不应该成为问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM