私は数週間前に更新された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;$!ba
GNUでのみ機能します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
に使用されない任意の文字列です。key
keybind
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
その場所で編集が行われ、元のファイルが変更されます。