我有以下脚本:
originalLine='<com.whatsapp.voipcalling.VideoCallParticipantViewLayout android:id="@id/video_participant_views" android:layout_width="fill_parent" android:layout_height="fill_parent"/>'
escParamToChange="android:layout_width"
value="10dip"
replacementLine=$(echo ${originalLine} | sed -E 's/'${escParamToChange}'=[^ ]*/'${escParamToChange}'="'${value}'"/')
echo ${replacementLine}
我试图将“android:layout_width”的值替换为“10dip”。
它工作正常,输出是:
<com.whatsapp.voipcalling.VideoCallParticipantViewLayout android:id="@id/video_participant_views" android:layout_width="10dip" android:layout_height="fill_parent"/>
但是当我将“escParamToChange”更改为“android:layout_height”时,这是我得到的输出:
<com.whatsapp.voipcalling.VideoCallParticipantViewLayout android:id="@id/video_participant_views" android:layout_width="fill_parent" android:layout_height="10dip"
最后一个“/>”也被删除。
我应该改变什么才能让它工作?
谢谢
答案1
尝试
replacementLine=$(echo ${originalLine} | sed -E 's/('${escParamToChange}'=)"[^"]+"/\1"'${value}'"/')
\1
替换捕获的组('${escParamToChange}'=)
(快捷方式)"[^"]+"
"
匹配以 开头,后跟一个或多个非“字符,最后是结束符的值"
适用于“sed (GNU sed) 4.4”
$ originalLine='<com.whatsapp.voipcalling.VideoCallParticipantViewLayout android:id="@id/video_participant_views" android:layout_width="fill_parent" android:layout_height="fill_parent"/>'
$ value="10dip"
$ for escParamToChange in android:layout_width android:layout_height; do echo ${originalLine} | sed -E 's/('${escParamToChange}'=)"[^"]+"/\1"'${value}'"/'; done
<com.whatsapp.voipcalling.VideoCallParticipantViewLayout android:id="@id/video_participant_views" android:layout_width="10dip" android:layout_height="fill_parent"/>
<com.whatsapp.voipcalling.VideoCallParticipantViewLayout android:id="@id/video_participant_views" android:layout_width="fill_parent" android:layout_height="10dip"/>
答案2
正如您所发现的,此命令删除了太多内容:
$ echo "${originalLine}" | sed -E 's/'${escParamToChange}'=[^ ]*/'${escParamToChange}'="'${value}'"/'
<com.whatsapp.voipcalling.VideoCallParticipantViewLayout android:id="@id/video_participant_views" android:layout_width="fill_parent" android:layout_height="10dip"
然而,这个命令是有效的:
$ echo "${originalLine}" | sed -E 's/'${escParamToChange}'=[^ /]*/'${escParamToChange}'="'${value}'"/'
<com.whatsapp.voipcalling.VideoCallParticipantViewLayout android:id="@id/video_participant_views" android:layout_width="fill_parent" android:layout_height="10dip"/>
问题是[^ ]*
与/>
.如果我们替换[^ ]*
为[^ /]
,则/>
将从匹配中排除。
上述的一个潜在问题是${escParamToChange}
和${value}
出现在命令行上且不带引号。如果它们包含空格或其他 shell 活动字符,则会导致不需要的结果。
替代方案:使用 awk
Awk 的优点是能够以合理的方式处理变量,这可以避免在尝试将 shell 变量填充到 sed 命令中时出现的一些潜在陷阱。在我看来,它还简化了引用问题:
$ echo "${originalLine}" | awk -v regex="${escParamToChange}=[^ /]*" -v new="${escParamToChange}=\"${value}\"" '{gsub(regex, new)} 1'
<com.whatsapp.voipcalling.VideoCallParticipantViewLayout android:id="@id/video_participant_views" android:layout_width="fill_parent" android:layout_height="10dip"/>
答案3
使用xq
,一个 XML 感知编辑工具https://kislyuk.github.io/yq/,修改属性:
replacementLine=$( printf '%s\n' "$originalLine" |
xq -x \
--arg attrib "@$escParamToChange" \
--arg value "$value" \
'(.[] | .[$attrib]) |= $value' )
printf '%s\n' "$replacementLine"
这将导入要在内部变量中更改的属性名称attrib
以及要将其更改为的值value
。路径表达式.[] | .[$attrib]
扩展到带有我们要更改的属性名称的所有属性(请注意,属性名称@
在命令行上带有前缀,这将其指定为属性而不是子节点)。