Xml 查找单个字符串的每个实例并将其替换为列表或文件中的另一个实例

Xml 查找单个字符串的每个实例并将其替换为列表或文件中的另一个实例,xml,linux,awk,sed,replace,Xml,Linux,Awk,Sed,Replace,我有一个很大的XML文件,其中包含字符串REPLACEME的多个实例。在第二个文件中,我有一个字符串列表(包含逗号),例如: 我想用第二个文件中的一个值替换第一个文件中的REPLACEME的每个实例,然后转到下一个实例 我已经研究了bash(sed、awk、perl)和Powershell。我被告知不应该使用for循环,而是使用文件循环并将文件解析回。所以我试过这个: file2=/file2.txt while IFS= read -r line; do printf '%s\n' "$l

我有一个很大的XML文件,其中包含字符串
REPLACEME
的多个实例。在第二个文件中,我有一个字符串列表(包含逗号),例如:

我想用第二个文件中的一个值替换第一个文件中的
REPLACEME
的每个实例,然后转到下一个实例

我已经研究了bash(sed、awk、perl)和Powershell。我被告知不应该使用for循环,而是使用文件循环并将文件解析回。所以我试过这个:

file2=/file2.txt
while IFS= read -r line; do
  printf '%s\n' "$line"
  sed '0,/REPLACEME/s//$line/' /file1.xml
done < "$file2"
file2=/file2.txt
而IFS=读取-r行;做
printf'%s\n'$行
sed“0,/REPLACEME/s/$line/”/file1.xml
完成<“$file2”
但它什么也没用。可能是因为XML文件有符号?它没有错误,只是什么都没做

如果我能找到一些可以实现替换结果的东西,是否愿意完全抛弃我的代码或切换解析器

编辑: 询问XML的示例。XML标记是KML文件的一部分,字符串是坐标点。示例如下:

<Placemark>
    <name>5005</name>
        <MultiGeometry>
            <Polygon>
                -snip-
            </Polygon>
            <Point>
            <gx:drawOrder>1</gx:drawOrder>
                <coordinates>REPLACEME</coordinates>
            </Point>
        </MultiGeometry>
</Placemark>

5005
-剪断-
1.
代替我

此文件中有数百个这样的条目,需要使用文件2中列表中的相应坐标进行填充。

听起来您只需要:

awk 'NR==FNR{a[NR]=$0; next} /REPLACEME/{sub(/REPLACEME/,a[++c])} 1' file2.txt file1.xml
通常的建议是在操作XML文件时使用XML感知工具,如xmlstarlet或xmllint,但我个人对这两种工具都不太了解,无法解决它们的这个问题,而且我认为这对于您所做的工作来说是不必要的,假设
REPLACEME
只在示例中所示的上下文中出现

在操作文本时,最好的建议不是“不要使用进行循环”,而是“不要使用shell循环”,因此在这种情况下使用while循环也是一种不好的方法。看

当做任何事情不只是操纵文本(例如从一个文件中读取URL列表来运行<代码> CURL上),那么一个shell循环可以是适当的,在这种情况下(也可以考虑<代码> XARGS),然后是的,您应该避免< <代码> < /COD> >,参见


您的sed脚本
sed'0,/REPLACEME/s/$line/'
不会让
$line
扩展,因为它在单引号中。

使用
sed
ed
的组合使用
sed
文件2.txt
创建
ed
命令:

(sed 's|.*|/REPLACEME/s/REPLACEME/&/|' file2.txt; echo '1,$p') | ed -s file1.xml
XML文件中的第一行
REPLACEME
file2.txt
的第一行替换,第二行被第二行替换,依此类推

如果要将更改保存到文件,而不是仅将其打印到标准输出,请将
echo'1,$p'
替换为
echo w

如果
file2.txt
中的行数多于
file1.xml
中的替换行数,
ed
将为每个标准错误打印一个问号。如果不想看到这些,请重定向到
/dev/null

$ (sed 's|.*|/REPLACEME/s/REPLACEME/&/|' file2.txt; echo '1,$p') | ed -s file1.xml 2>/dev/null
<Placemark>
    <name>5005</name>
        <MultiGeometry>
            <Polygon>
                -snip-
            </Polygon>
            <Point>
            <gx:drawOrder>1</gx:drawOrder>
                <coordinates>58,-21,0</coordinates>
            </Point>
        </MultiGeometry>
</Placemark>
$(sed's |。*|/REPLACEME/s/REPLACEME/&/|'file2.txt;echo'1,$p')| ed-s file1.xml 2>/dev/null
5005
-剪断-
1.
58,-21,0

如果不是针对
2>/dev/null
,您的示例文件也会生成一个
,因为
file2.txt
有两行,XML文件中只有一个REPLACEME。

一个值表示
58,-21,0
58
-21
0
依此类推?您需要将修改后的文件放在哪里1-将其写出?或者更新当前文件1?您已经展示了第二个文件的示例。您还可以显示XML文件的示例以及与此对应的输出吗?不,单个值为“58,-21,0”。我认为符号和逗号可能会造成问题,所以我把它们包括在内。XML示例是这样的:5000 REPLACEME上述内容将是一个文件的一部分,其中有500多个条目都需要替换。非常感谢您为我添加有关shell循环和脚本问题的上下文。我感谢你为教育我所做的额外努力,而不仅仅是提供答案。我正确地假设我需要将awk的输出通过管道传输回一个文件?通过管道将其传输到新文件中的最佳做法是,还是通过管道将其传输回“file1.xml”也是可以接受的?另外一个问题我知道,但为了完整起见…不客气。切勿将任何命令的输出重定向回输入文件,因为这样做会在命令运行前清空输入文件。对于任何给定的命令,请执行
cmd file>tmp&&mv tmp file
。@EdMorton就
0、/RE/
的第二点进行了说明,与awk不同,sed将数字地址解析为行号。GNU sed允许,因此
/RE/
可以在第一行结束范围(而
1,/RE/
不能)。啊,我明白了。范围表达式本质上是邪恶的,所以我从不使用它们。我应该这么说,而不是猜测它的意思:-)!我把那句话从我的回答中删掉了,谢谢。谢谢肖恩。我欣赏非破坏性的例子,帮助分解和测试它。但是这个命令似乎不起作用;它只打印了两行,是吗?性格Ed的答案是可行的,但我不介意理解sed和Ed在这个场景中做了什么?@TylerJones如果您在file2.txt中的行数比file1.xml中的REPLACEME行数多,您将在标准错误上得到问号。它们可以被忽略。如果不想看到标准错误,请将其重定向到/dev/null。
$ (sed 's|.*|/REPLACEME/s/REPLACEME/&/|' file2.txt; echo '1,$p') | ed -s file1.xml 2>/dev/null
<Placemark>
    <name>5005</name>
        <MultiGeometry>
            <Polygon>
                -snip-
            </Polygon>
            <Point>
            <gx:drawOrder>1</gx:drawOrder>
                <coordinates>58,-21,0</coordinates>
            </Point>
        </MultiGeometry>
</Placemark>