SED 替换字符串内的字符串

SED 替换字符串内的字符串

我有以下脚本:

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]扩展到带有我们要更改的属性名称的所有属性(请注意,属性名称@在命令行上带有前缀,这将其指定为属性而不是子节点)。

相关内容