如何在bash中执行以空格开头并包含引号的regex测试



我正在尝试编写一个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,我将使用sedfill: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}

修复:

  1. 转义正则表达式中的空白:=~ +id *= *
  2. 对于sed,切换到模式中变量的双引号
  3. 同样对于sed,我添加了-E扩展正则表达式标志,以便支持否定集[^;]

Re:XML,我将把可用的CLI友好的XML解析器列表与用户机器上常见的工具集进行比较。

最新更新