次のスクリプトがあります。
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}'=)
(ショートカット)"[^"]+"
"
一致は「ではなく、1つ以上の文字で始まり、その後に終端値が続きます。"
「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"/>
問題[^ ]*
はです。に/>
置き換えると、一致から除外されます。[^ ]*
[^ /]
/>
上記の潜在的な問題の1つは、${escParamToChange}
コマンド${value}
ラインに引用符なしで表示されることです。スペースやその他のシェルアクティブ文字が含まれていると、不要な結果が生じる可能性があります。
代替案:awkを使用してください
Awkの利点は、変数を合理的な方法で処理するため、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]
変更する属性名を持つすべての属性に展開されます(属性名は、子@
ノードではなく属性として指定するコマンドラインの接頭辞です)。