Grep

Bash 輸出兩個相鄰的結果

  • October 23, 2018

我有一個來自 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(格式良好的最小範例會很有用),您應該能夠像這樣使用xmllintwith --xpathxmllint>= 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') 的輸出。

引用自:https://unix.stackexchange.com/questions/477008