Sed(OSX)将包含给定字符串的文本块替换为其他文本块



我想用其他文件替换所有包含Test.bundle的行(这些行分组在一个块中(

来自

<ItemGroup>
<BundleResource Include="Resourcessome_other_file.json" />
<BundleResource Include="ResourcesTest.bundleone.png" />
<BundleResource Include="ResourcesTest.bundletwo.png" />
<BundleResource Include="ResourcesTest.bundlethree.png" />
</ItemGroup>

<ItemGroup>
<BundleResource Include="Resourcessome_other_file.json" />
<BundleResource Include="ResourcesTest.bundlefour.png" />
<BundleResource Include="ResourcesTest.bundlefive.png" />
<BundleResource Include="ResourcesTest.bundlesix.png" />
<BundleResource Include="ResourcesTest.bundleseven.png" />
</ItemGroup>

我做了什么

res=$(find Resources/Test.bundle -type f | sed 's/\///g' | xargs -I {} echo "<BundleResource Include="{}" />") #get new files, change path delimiters, wrap file names in output pattern
sed -E -i '' '/Test.bundle/,/ItemGroup/c
BUNDLE_PLACEHOLDER' file.ext #remove whole block from first line containing Test.bundle to closing ItemGroup and replace with placeholder
sed -E -i '' "s:BUNDLE_PLACEHOLDER:$res:" file.ext #replace with new block

由于"extra characters after at the end of c command"的原因,我无法在第三个命令中一次更改它,所以我将它更改为试图在下一个命令中替换的字符串占位符。这也是由于unescaped newline inside substitute pattern而失败的,我目前正在尝试解决这个问题。还缺少稍后将添加的结束ItemGroup标记。

使用sed还有其他选择吗?

我可以只捕获包含Test.bundle的组而不捕获正在关闭的ItemGroup吗?

如何转义换行符以满足替换模式?

目前尚不清楚您真正想要匹配的内容,但这可能是您想要的:

awk '
NR==FNR {
new = new $0 ORS
next
}
/Test.bundle/ {
printf "%s", new
new = ""
next
}
{ print }
' new old

例如:

$ cat old
<ItemGroup>
<BundleResource Include="Resourcessome_other_file.json" />
<BundleResource Include="ResourcesTest.bundleone.png" />
<BundleResource Include="ResourcesTest.bundletwo.png" />
<BundleResource Include="ResourcesTest.bundlethree.png" />
</ItemGroup>
$ cat new
<BundleResource Include="ResourcesTest.bundlefour.png" />
<BundleResource Include="ResourcesTest.bundlefive.png" />
<BundleResource Include="ResourcesTest.bundlesix.png" />
<BundleResource Include="ResourcesTest.bundleseven.png" />

$ awk '
NR==FNR {
new = new $0 ORS
next
}
/Test.bundle/ {
printf "%s", new
new = ""
next
}
{ print }
' new old
<ItemGroup>
<BundleResource Include="Resourcessome_other_file.json" />
<BundleResource Include="ResourcesTest.bundlefour.png" />
<BundleResource Include="ResourcesTest.bundlefive.png" />
<BundleResource Include="ResourcesTest.bundlesix.png" />
<BundleResource Include="ResourcesTest.bundleseven.png" />
</ItemGroup>

首先,sed并不是您的最佳选择,但由于您要求提供sed
这是一个粗糙的第一回合。

$: cat new
<ItemGroup>
<BundleResource Include="Resourcessome_other_file.json" />
<BundleResource Include="ResourcesTest.bundlefour.png" />
<BundleResource Include="ResourcesTest.bundlefive.png" />
<BundleResource Include="ResourcesTest.bundlesix.png" />
<BundleResource Include="ResourcesTest.bundleseven.png" />
</ItemGroup>
$: cat old
stuff before
...
more stuff
<ItemGroup>
<BundleResource Include="Resourcessome_other_file.json" />
<BundleResource Include="ResourcesTest.bundleone.png" />
<BundleResource Include="ResourcesTest.bundletwo.png" />
<BundleResource Include="ResourcesTest.bundlethree.png" />
</ItemGroup>
stuff after
...
more stuff.
$: sed -n '/<ItemGroup>/,/<[/]ItemGroup>/{ /<ItemGroup>/h;
/<[/]ItemGroup>/{ H; s/^.*//; x; /Test[.]bundle/{ s/^.*/cat new/e; }; p; d; }
H; d; }; p; ' old
stuff before
...
more stuff
<ItemGroup>
<BundleResource Include="Resourcessome_other_file.json" />
<BundleResource Include="ResourcesTest.bundlefour.png" />
<BundleResource Include="ResourcesTest.bundlefive.png" />
<BundleResource Include="ResourcesTest.bundlesix.png" />
<BundleResource Include="ResourcesTest.bundleseven.png" />
</ItemGroup>
stuff after
...
more stuff.

这显然对您的文件结构做了一些简单的假设。

awk:中的相同逻辑

awk 'NR == FNR { new=new$0"n"; next; }
/<ItemGroup>/,/<[/]ItemGroup>/{ grp=grp$0"n";
if ($0 ~ "</ItemGroup>") { if (grp ~ "Test.bundle") { print new } else { print grp } grp="" } else next;
} 1' new old

最新更新