Grep
Bash 輸出兩個相鄰的結果
我有一個來自 xmllint 和 egrep 的輸出,我想列印兩個相鄰的欄位。例如
(xmlinput) xmllint --format | egrep reference\|sourcefile <reference>ItemX</reference> <sourcefile>://filepath/blah/blah/</sourcefile> <reference>ItemY</reference> <sourcefile>://filepath/blah/blah/</sourcefile> . . <reference>ItemW</reference> <sourcefile>://filepath/blah/blah/</sourcefile>
有沒有辦法將引用和源文件元素彼此相鄰輸出?例如
(xmlinput) xmllint --format | egrep reference\|sourcefile <reference>ItemX</reference><sourcefile>://filepath/blah/blah/</sourcefile> <reference>ItemY</reference><sourcefile>://filepath/blah/blah/</sourcefile> . . <reference>ItemW</reference><sourcefile>://filepath/blah/blah/</sourcefile>
[your command] | paste -d '' - -
將加入連續的行。
一旦您開始
grep
在 XML 上使用,您就會對輸入做出假設,並且您將(幾乎可以肯定)不再有有效的 XML 輸出,因此有時這不是最好的方法。也就是說,阻力最小的路徑通常涉及
grep
,因此根據您的 XML(格式良好的最小範例會很有用),您應該能夠像這樣使用xmllint
with--xpath
(xmllint
>= 2.7.7 以獲得--xpath
支持):xmllint --xpath "//reference|//sourcefile" input.xml | pcregrep -o "(<reference>.*?</sourcefile>)"
where使用與您感興趣的元素中的任何一個(作為邏輯“或”)匹配的XPath表達式
xmllint
提取元素(以選擇輸入中任何位置的所有匹配元素)。(非 XML 感知)(而不是)將每對元素與分組匹配,並每行輸出一個匹配的組。這裡要注意的一點是正則表達式,它是 PCRE非貪婪匹配,因此它匹配指定標籤之間的最小文本量,而不是一次性匹配整行(將所有內容轉儲到一行)。|``//``pcregrep``egrep``.*?``xmllint --xpath ...
使用 grep 有點“作弊”,我們正在對輸入進行假設,但
xmllint
正在做大部分繁重的工作。這種方法可能會導致未來的解析問題,因為XML 不是“正常的”,並且正則表達式不是完成這項工作的最佳工具。做到這一點的巧妙方法是使用XMLStarlet:
xml select -t -m '//*' \ --if 'local-name()="reference"' -c . \ --elif 'local-name()="sourcefile"' -c . -o $'\n' input.xml
這將搜尋所有元素 (
//*
),在匹配<reference>
該節點時將其複製到輸出 (-c .
),否則在匹配<sourcefile>
該節點時將其複製到帶有額外換行符輸出 (-o $'\n'
) 的輸出。