私のLinuxコンピュータには次のファイルがあります。
<names>
<first_name>Mohammed Sani</first_name>
<last_name>ABACHA</last_name>
<aliases>
<alias>ABACHE,Mohammed Sani</alias>
<alias>SANI,Mohammed</alias>
</aliases>
<low_quality_aliases>
<alias xsi:nil="true"/>
</low_quality_aliases>
<alternative_spelling xsi:nil="true"/>
</names>
次のコマンドを使用して名前を印刷しますが、名前のみを印刷します。
sed -n 's:.*<first_name>\(.*\)</first_name>.*:\1:p' 'test.xml' > name.txt
姓を追加するにはどうすればよいですか?
答え1
名前と姓データが同じ行にあり、その間にタブがあることを望んでいるとします。
使用xmlstarlet
:
xmlstarlet sel -t -m '/names' \
-v 'first_name' -nl \
-v 'last_name' -nl file.xml 2>/dev/null |
paste - -
このコマンドは、そのノードとその下のノードの値を解析し、それぞれxmlstarlet
1行ずつ出力します。first_name
last_name
names
タブ文字を区切り文字として使用して、出力の2行を1行に貼り付けますpaste
。たとえば、withを使用する-d ','
とpaste
、カンマ区切りの出力を取得できます。
/dev/null
後でドキュメントにxmlstarlet
正しいいくつかの偽の名前空間宣言があるため、標準エラーストリームにリダイレクトします。
xq
以下で使用https://kislyuk.github.io/yq/:
xq -r '.names | [ .first_name, .last_name ] | @tsv' file.xml
これは@tsv
演算子を使用してタブ区切りの出力を生成します。上記のコードと同じデータを出力しますxmlstarlet
が、XPath式の代わりに式を使用しますjq
。
代わりに、完全に引用されたCSV出力を@tsv
取得してください。@csv
答え2
2番目のコマンドを追加できますs
。
sed -n 's:.*<first_name>\(.*\)</first_name>.*:\1:p;s:.*<last_name>\(.*\)</last_name>.*:\1:p' 'test.xml' > name.txt
または拡張正規表現を使用してください。
sed -En 's:.*<(first|last)_name>(.*)</\1_name>.*:\2:p' 'test.xml' > name.txt
更新:両方の名前を同じ行に出力するように要求
同じ行に出力を配置するには、別のスクリプトを介して空白の行にパイプするだけです。
sed -En 's:.*<(first|last)_name>(.*)</\1_name>.*:\2:p' test.xml | sed 'H;1h;$!d;g;s/\n/ /g' > name.txt
パターン空間のすべての行を連結するために使用されますH,1h;$1d;g
(H
すべての行を予約済みスペースに追加し、1h
前の改行を防ぐために最初の行の予約済みスペースを上書きし、最後の行を除くすべての$!d
行の処理を停止し、 、g
予約された空間内容をパターン空間に移動)。次に、s/\n/ /g
すべての改行を空白に置き換えます。あなたの場合は、g
常に2行しかないと確信している場合はそれを削除できます。
LinuxではGNUがあり、同じ結果がsed
得られます。sed -z 's/\n/ /g'
よりエレガントに、ファイルで複数の名前のペアを処理できる場合は、次のこともできます。
sed -e '/.*<first_name>\(.*\)<\/first_name>.*/{s//\1/;h;}' -e '/.*<last_name>\(.*\)<\/last_name>.*/!d;s//\1/;H;g;s/\n/ /' 'test.xml' > name.txt