[英]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(/"/, """, dbpass);
但是有一个问题:你如何处理
"
密码?可能做一些像dbpass = ENVIRON["DB_PASS"]; gsub(/"/, """, 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/KARDB
的Context
节点下的每个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.