テキストファイル(XML)で改行文字を含む文字列を交換するためのスクリプト

テキストファイル(XML)で改行文字を含む文字列を交換するためのスクリプト

私は数週間前に更新されたArchを使用しています。使用されたパッケージは

  • アーチ 6.0.10-arch2-1
  • BASH 5.1.16(1) - リリース
  • グヌス 4.9
  • グヌ grep 3.8
  • 3.6.1 アンボクシング

私のOpenboxrc.xmlテキストファイルには2つの行があります。

<!-- <keybind key="Right"> -->

<keybind key="s-Up">

スクリプトを使用して、上の2行と下の2行を頻繁に切り替え/交換したいと思います。

<!-- <keybind key="s-Up"> -->

<keybind key="Right">

rc.xmlこれにより、キーバインディング設定テキストファイル()を毎回退屈に編集することなく、キーバインディングをすばやく変更できます。

これまで私のスクリプトは次のようになりますが、近いことを知っていますが、うまくいきません。

私はこのスイッチをどのように実装するかはあまり興味がありませんが、これに多くの時間を費やしているので、以下のスクリプトがうまくいくことをお勧めします。

以下の式は、sedテキスト交換操作を通常どおり実行します。

ステートメントは、条件が満たされると最初のifスワップを実行しますが、条件がsed満たされない場合は2番目のスワップを実行しないように見えることが問題です。sed

var_a=""

#var_a=$(grep -zoP  "<\!\-\- <keybind key=\"Right\"> \-\->\n\n<keybind key=\"s-Up\">" /home/kes/Dropbox/lubuntu-rc.xml | sed ':a;N;$!ba;s|\n\n||g')

var_a=$(grep -zoP  "<\!\-\- <keybind key=\"Right\"> \-\->\n\n<keybind key=\"s-Up\">" /home/kes/Dropbox/lubuntu-rc.xml | tr -d '\n' )

# result of grep is
# <!-- <keybind key="Right"> --><keybind key="s-Up">

echo $var_a; sleep 0.5

#if [[ -z ! "$var_a" ];then
if [[ '$var_a'=='<!-- <keybind key="Right"> --><keybind key="s-Up">' ]]; then

   sed -ie ':a;N;$!ba;s|<!-- <keybind key="Right"> -->\n\n<keybind key="s-Up">|<!-- <keybind key="s-Up"> -->\n\n<keybind key="Right">|g' /home/kes/Dropbox/lubuntu-rc.xml

else

   sed -ie ':a;N;$!ba;s|<!-- <keybind key="s-Up"> -->\n\n<keybind key="Right">|<!-- <keybind key="Right"> -->\n\n<keybind key="s-Up">|g' /home/kes/Dropbox/lubuntu-rc.xml

fi

答え1

実際、一重引用符は'$var_a'変数を拡張しないため、この条件は決して満たされません。したがって、リテラル文字列は$var_a他のリテラル文字列と同じではありません。

二重引用符を使用すると機能します。しかし、あなたのスクリプトにいくつかの説明を追加したいと思います。

(1)まず、grepそれから得られた結果に基づいて条件を構築し、grep最後に2つの異なるsedスクリプトを使用します。これによりエラーが発生する可能性があります。実際にsedすべての作業を一人で行うことになります。

sed -ie ':a;N;$!ba
  s|<!-- <keybind key="Right"> -->\n\n<keybind key="s-Up">|<!-- <keybind key="s-Up"> -->\n\n<keybind key="Right">|g
  t
  s|<!-- <keybind key="s-Up"> -->\n\n<keybind key="Right">|<!-- <keybind key="Right"> -->\n\n<keybind key="s-Up">|g' \
  /home/kes/Dropbox/lubuntu-rc.xml

最初の置換が行われた場合はtスクリプトの最後にジャンプし、そうでない場合は別の置換を実行します。すでに含まれていgrepますif

(2)すべての行を収集する方法は:a;N;$!baGNUでのみ機能しますsed。 POSIX規格によると、コロンの後ろのすべての項目はジャンプ表示になり、例外ではないためです;。 GNUがあるので問題ありません。ただし、部品なしで一度に穴ファイルを処理することを選択するsedこともできます。-z携帯性を好む場合は、H;1h;$!d;xストレージスペースも同じことができます。

(サム)私の考えでは、gこの行が一度だけ存在するため、グローバルフラグが重複しているようです。そうですか?

(4)同じ内容を繰り返し書き込むとエラーが発生し、読みにくくなります。部品にタグを付けて\(\)参照して部品を再利用するのはどうですか\1

sed -iz 's|<!-- \(<keybind key="\)Right"> -->\n\n\1s-Up">|<!-- \1s-Up"> -->\n\n\1Right">|
  t
  s|<!-- \(<keybind key="\)s-Up"> -->\n\n\1Right">|<!-- \1Right"> -->\n\n\1s-Up">|' \
  /home/kes/Dropbox/lubuntu-rc.xml

(5)実際、ファイル全体を1つとして扱う必要はありません(大きなファイルもオーバーフローする可能性があります)。このN;P;Dスキームを使用して、3行の連続した行をすべて一緒に処理します(通常、2行を一緒に処理して1N拡張するには追加します)。 3つのOK):

sed -i '1N;N
  s|<!-- \(<keybind key="\)Right"> -->\n\n\1s-Up">|<!-- \1s-Up"> -->\n\n\1Right">|
  t
  s|<!-- \(<keybind key="\)s-Up"> -->\n\n\1Right">|<!-- \1Right"> -->\n\n\1s-Up">|;
  P;D' /home/kes/Dropbox/lubuntu-rc.xml

これを簡単にすることもできますが、ファイルの内容に関する追加情報が必要です。

答え2

XML文書の形式が正しく、構文が正しいと仮定すると、XMLプロセッサを使用してxmlstarlet値を切り替えることができます。

文書内でコメント化されたXMLを無視し、次に最初にkey各ノードのすべての属性をkeybind値から(他の値を持つ属性は影響を受けません)Rightに変更してこれを行います。次に、temporary同じプロパティをからにs-Up変更Rightし、最後にからにtemporary変更しますs-Up。この文字列は、ノードの属性temporaryに使用されない任意の文字列です。keykeybind

Rightこれは値を効果的に変更するか、s-Upその逆に置き換えます。

xmlstarlet edit \
    --var attr '//keybind/@key' \
    --update '$attr[.="Right"]'     --value temporary \
    --update '$attr[.="s-Up"]'      --value Right \
    --update '$attr[.="temporary"]' --value s-Up \
   file.xml

これで文書は次のように変わります。

<?xml version="1.0"?>
<root>
  <keybind key="s-Up"/>
  <keybind key="s-Down"/>
  <keybind key="Right"/>
</root>

...入力する

<?xml version="1.0"?>
<root>
  <keybind key="Right"/>
  <keybind key="s-Down"/>
  <keybind key="s-Up"/>
</root>

--inplaceコマンドラインで単語の直後に挿入すると、editその場所で編集が行われ、元のファイルが変更されます。

関連情報