Har*_*cle 159 sed quoting regular-expression
我有一个包含以下内容的文件:
<username><![CDATA[name]]></username>
<password><![CDATA[password]]></password>
<dbname><![CDATA[name]]></dbname>
Run Code Online (Sandbox Code Playgroud)
我需要制作一个脚本,将第一行中的“name”更改为“something”,将第二行中的“password”更改为“somethingelse”,将第三行中的“name”更改为“somethingdifferent”。我不能依赖这些在文件中出现的顺序,所以我不能简单地用“something”替换第一次出现的“name”,用“somethingdifferent”替换第二次出现的“name”。我实际上需要搜索周围的字符串,以确保我找到并替换了正确的东西。
到目前为止,我已尝试使用此命令来查找和替换第一个“名称”出现:
sed -i "s/<username><![CDATA[name]]><\/username>/something/g" file.xml
Run Code Online (Sandbox Code Playgroud)
但是它不起作用所以我认为其中一些字符可能需要转义等。
理想情况下,我希望能够使用正则表达式来匹配两个“用户名”出现并仅替换“名称”。像这样的东西,但有sed:
<username>.+?(name).+?</username>
Run Code Online (Sandbox Code Playgroud)
并将括号中的内容替换为“某物”。
这可能吗?
lge*_*get 282
sed -i -E "s/(<username>.+)name(.+<\/username>)/\1something\2/" file.xml
Run Code Online (Sandbox Code Playgroud)
我想,这就是你要找的。
解释:
\1,\2等在第二部分是在第一部分捕获的第i组的引用(编号从1开始)-E启用扩展的正则表达式(需要+和分组)。evi*_*oup 19
sed -e '/username/s/CDATA\[name\]/CDATA\[something\]/' \
-e '/password/s/CDATA\[password\]/CDATA\[somethingelse\]/' \
-e '/dbname/s/CDATA\[name\]/CDATA\[somethingdifferent\]/' file.txt
Run Code Online (Sandbox Code Playgroud)
该/username/前s告诉sed只工作在包含字符串“用户名”行。
man*_*ork 11
如果sed不是硬性要求,最好使用专用工具。
如果您的文件是有效的 XML(不仅仅是那 3 个看起来像 XML 的标签),那么您可以使用XMLStarlet:
xml ed -P -O -L \
-u '//username/text()' -v 'something' \
-u '//password/text()' -v 'somethingelse' \
-u '//dbname/text()' -v 'somethingdifferent' file.xml
Run Code Online (Sandbox Code Playgroud)
上述内容也适用于使用正则表达式难以解决的情况:
以上简单演示:
bash-4.2$ cat file.xml
<sith>
<master>
<username><![CDATA[name]]></username>
</master>
<apprentice>
<username><![CDATA[name]]></username>
<password>password</password>
<dbname foo="bar"><![CDATA[name]]></dbname>
</apprentice>
</sith>
bash-4.2$ xml ed -O -u '//apprentice/username/text()' -v 'something' -u '//password/text()' -v 'somethingelse' -u '//dbname/text()' -v 'somethingdifferent' file.xml
<sith>
<master>
<username><![CDATA[name]]></username>
</master>
<apprentice>
<username><![CDATA[something]]></username>
<password>somethingelse</password>
<dbname foo="bar"><![CDATA[somethingdifferent]]></dbname>
</apprentice>
</sith>
Run Code Online (Sandbox Code Playgroud)
您需要\[.*^$/在命令的正则表达式部分s和\&/替换部分中引用,并加上换行符。正则表达式是一个基本的正则表达式,此外还需要引用s命令的分隔符。
您可以选择不同的分隔符以避免引用/。您必须改为引用该字符,但通常更改分隔符的目的是选择要替换的文本或替换文本中未出现的字符。
sed -e 's~<username><!\[CDATA\[name\]\]></username>~<username><![CDATA[something]]></username>~'
Run Code Online (Sandbox Code Playgroud)
您可以使用组来避免重复替换文本中的某些部分,并适应这些部分的变化。
sed -e 's~\(<username><!\[[A-Z]*\[\)name\(\]\]></username>\)~\1something\2~'
sed -e 's~\(<username>.*[^A-Za-z]\[\)name\([^A-Za-z].*</username>\)~\1something\2~'
Run Code Online (Sandbox Code Playgroud)
小智 5
$ sed -e '1s/name/something/2' \
-e '3s/name/somethingdifferent/2' \
-e 's/password/somethingelse/2' sample.xml
Run Code Online (Sandbox Code Playgroud)
您可以简单地使用“s”前面的数字中的地址,该数字表示行号。
最后的数字也告诉sed替换第二个匹配而不是替换第一个匹配。