
以下のファイルを整理(所定の場所で編集)しようとしています。
<id>474488</id>
<name>Shawn</name>
<nr>143385</nr>
<id>474490</id>
<name>Bob</name>
<nr>.27. 43-88</nr> # this is the line of interest
<id>474568</id>
<name>Jim</name>
<nr>
</nr> # sometimes there will be no value and a closing tag on a newline, this can be ignored
....
希望の出力:
<id>474488</id>
<name>Shawn</name>
<nr>143385</nr>
<id>474490</id>
<name>Bob</name>
<nr>274388</nr> # note that nr data has been cleaned to digits only
<id>474568</id>
<name>Jim</name>
<nr>
</nr>
....
つまり、<nr> </nr>
ラベルに含まれるデータから数字以外の文字をすべて削除したり、特定の文字を削除したいとします。
私のコード:
sed -Ee '/<nr>/ s/>(.*)</>\1</g' test1.txt
これがすること:
<nr>
次の行のみを選択してください。その中のラベルとコンテンツを置き換えます(グループ1のコンテンツキャプチャ=グループ1のコンテンツキャプチャで何をすべきかわからないため、変更はありません)。
また、理想的には を交換したくはありませんが、sed から sed 以降および以前に> <
開始するよう指示するのは sed では不可能に見えます。>
<
何を追加する必要があります(しかし方法がわかりません):
挿入する前に、キャプチャグループ1の内容をフィルタリングします(削除.
と-
数字のみを許可)。whitespace
どうすればいいですか?
他のツールを使用する必要がありますか?
答え1
これはXMLフラグメントのように見えます。<root/>
次のXMLを持つように閉じる要素を追加してから、XML編集ツールを使用できます。
xmlstarlet ed -u '//nr' -x 'translate(text(), "- .", "")' file.xml
<?xml version="1.0"?>
<root>
<id>474488</id>
<name>Shawn</name>
<nr>143385</nr>
<id>474490</id>
<name>Bob</name>
<nr>274388</nr>
<id>474568</id>
<name>Jim</name>
<nr>
</nr>
</root>
ここで重要な部分はXPath translate()
機能です。ある文字列の文字を別の文字列の文字に置き換えるという点で、UNIX / Linuxコマンドと同様に機能しますtr
(最初のパラメータは計算する値です)。
私はそれをnr
作業のためのフックとして使用します。必要に応じて要素パスがより正確になることがあります(私の例でも/root/nr
機能します)。
実際にファイルを処理するフィルタリングツールはほとんどありません。一時ファイルを作成し、それを使用して元のファイルを置き換えます。この場合は、直接実装する必要があります。
xmlstarlet ... file.xml >file.xml.tmp && mv -f file.xml.tmp file.xml
答え2
これがXMLなどの適切に構造化された言語である場合は、実際には専用のパーサーを使用する必要があります(たとえばxmlstarlet
、これを考慮してください)。つまり、ファイルがメモリに入るほど小さい場合は、コメントで述べたようにフィールドが空の場合にのみ改行があるため、置き換えが不要であると仮定すると、次のことができます。方法:
$ sed '/<nr>/{s/[. -]*//g}' file
<id>474488</id>
<name>Shawn</name>
<nr>143385</nr>
<id>474490</id>
<name>Bob</name>
<nr>274388</nr>#thisisthelineofinterest
<id>474568</id>
<name>Jim</name>
<nr>
</nr>
....
より複雑な場合に適切なパーサーを使用できない場合は、Perlを使用してください。
$ perl -nle '$k=1 if /<nr>/; if($k){s/[. -]//g}; $k=0 if /<\/nr>/; print' file
<id>474488</id>
<name>Shawn</name>
<nr>143385</nr>
<id>474490</id>
<name>Bob</name>
<nr>274388</nr>#thisisthelineofinterest
<id>474568</id>
<name>Jim</name>
<nr>
</nr>
....
ただし、次のように同じ行に複数のラベルがある場合、上記の操作は失敗します。
<nr>143385</nr><name>Shawn - Mary</name>
この場合-
の値からも削除されます<name>
。この極端なケースは、パーサーが実際に最良の選択である理由です。
perl
およびオプションの場合は、ファイルの内部編集をsed
使用できます。-i
sed -i '/<nr>/{s/[. -]*//g}' file
perl -i -nle '$k=1 if /<nr>/; if($k){s/[. -]//g}; $k=0 if /<\/nr>/; print' file