我正在尝试编写一个bash脚本,该脚本将更改SVG文件中某些元素的fill
颜色。我对shell脚本没有经验,但我对正则表达式(…在JS中(很在行。
这是我要修改的SVG标记:
<!-- is the target because its ID is exactly "the.target" -->
<path id="the.target" d="..." style="fill:#000000" />
这是我迄今为止得到的bash代码:
local newSvg="" # will hold newly-written SVG file content
while IFS="<$IFS" read tag
do
if [[ "${tag}" =~ +id *= *"the.target" ]]; then
tag=$(echo "${tag}" | sed 's/fill:[^;];/fill:${color};/')
fi
newSvg="${newSvg}${tag}"
done < ${iconSvgPath} # is an argument to the script
说明:我使用read
(通过自定义IFS
在<
上拆分文件(逐标记读取SVG内容。对于每个标记,我测试它是否包含一个具有我想要的确切值的id
属性。如果没有,我会按原样将此标记添加到newSvg
字符串中,稍后将其写入文件。如果标签确实具有所需的ID,我将使用sed
将fill:STUFF;
替换为fill:${myColor};
。(请注意,我的sed
也失败了,但这不是我在这里要问的。(
它没有找到与测试[[ "${tag}" =~ +id *= *"the.target" ]]
正确的线路。
如果我将测试更改为[[ "${tag}" =~ "the.target" ]]
,它将成功。
我对工作版本不满意,因为它太脆了。虽然我不打算支持所有XML的灵活性,但我希望容忍语义上不相关的空白,以及标记中任何位置的id属性。理想情况下,我想写的正则表达式应该表示:
id
(前面至少有一个空格(- 后面是零个或多个空白
- 然后是
=
- 后面是零个或多个空白
- 然后是
"the.target"
我认为我没有在[[ ... =~ REGEX ]]
构造中正确地定义正则表达式,但我在网上看到的答案都没有使用任何分隔符。在javascript中,正则表达式的文字是有界的(例如/ +id *= *"the.target"/
(,因此用您关心的空白字符开始正则表达式很简单。此外,JS没有任何魔法re:*
,而bash是对星号50%的魔法处理。
感谢您的帮助。我的备份计划可能是尝试使用awk
(我并不擅长(。
EDIT:我的sed真的很接近。我忘记在[^;]
集合之后添加+
。哦。
如果在变量中定义正则表达式模式,会容易得多:
tag=' id = "the.target"'
pattern=' +id *= *"the.target"'
if [[ $tag =~ $pattern ]]; then
echo matched.
fi
感谢您给我们一个明确的例子,regex是而不是解决此问题的方法。
SVG文件是一个XML文件,修改这些文件的一个可能工具是xmlstarlet。
试试这个我称之为modifycolor:的脚本
#!/bin/bash
# invoke as: modifycolor <svg.file> <target_id> <new_color>
xmlstarlet edit
--update "//path[@id = '$2']/@style" --value "fill:#$3"
"$1"
假设svg文件是test.svg,则将其调用为:
./modifycolor test.svg the.target ff0000
你会对结果感到惊讶。
如果你想在bash脚本中粘贴一段代码,可以试试这个:
target="the.target"
newSvg=$(xmlstarlet edit
--update "//path[@id = '${target}']/@style" --value "fill:#${myColor}"
"${iconSvgPath}")
感谢大家指出我bash-fu中的错误,我想出了这个代码,它实现了我所说的我想要的。我不会将其标记为可接受的答案,因为正如人们所观察到的,regex是对XML进行操作的糟糕方法。为子孙后代分享这一点。
local newSvg="" # will hold newly-written SVG code
while IFS="<$IFS" read tag
do
if [[ "${tag}" =~ +id *= *"the.target" ]]; then
tag=$(echo "${tag}" | sed -E 's/fill:[^;]+;/fill:'"${color}"';/')
fi
newSvg="${newSvg}${tag}"
done < ${iconSvgPath}
修复:
- 转义正则表达式中的空白:
=~ +id *= *
- 对于
sed
,切换到模式中变量的双引号 - 同样对于
sed
,我添加了-E
扩展正则表达式标志,以便支持否定集[^;]
Re:XML,我将把可用的CLI友好的XML解析器列表与用户机器上常见的工具集进行比较。