2014-07-19 62 views
1

編輯:在此之前沒有提到的是在OS X中執行如何從文件中刪除文本塊

我試圖創建一個bash腳本將從一個文件中刪除一些塊和保存結果到另一個。

該文件的內容我想過濾應該是這樣的:

<element> 
    <subElement name="leaveme"/> 
    <subElement name="leaveme"/> 
    <subElement name="leaveme"/> 
</element> 
<element> 
    <subElement name="removeme"/> 
    <subElement name="removeme"/> 
    <subElement name="removeme"/> 
</element> 
<element> 
    <subElement name="leaveme"/> 
    <subElement name="leaveme"/> 
    <subElement name="leaveme"/> 
</element> 

我想刪除是包括<element></element>標籤包含的子元素<subElement name="removeme"/>

它保證沒有組將有組「removeme」和「leaveme」元素混合在一起。

我知道如何使用正則表達式這樣做:

<element>(?:(?!/elem).)*"removeme".*?</element> 

但我真的失去了如何做一個shell腳本,發現了約sed的一些信息,但並不瞭解如何實現這一點。

謝謝。

+0

'sed'對於這項任務並不是很好。試試'awk'。看看Jotne的答案(或者可能是我的)[這裏](http://stackoverflow.com/questions/24814783/extract-multiple-lines-on-either-end-of-pattern-which-are-closed-by -an-IDENTIF/24815006?noredirect = 1個#comment38527405_24815006)。它基本上與你想要的相反,但你應該能夠適應它。 – ooga

+0

我確實看過它,但它只是使用一些分隔符來定義刪除的內容,我需要知道內容是否包含特定文本以確定是否刪除它,是否可以適應它? – Gusman

+0

它使用兩個分隔符(比如你的''標籤)和內容。我認爲這很容易適應。我會嘗試一下,讓它知道它是否適用,但我認爲是。 – ooga

回答

1

下面的想法(基於Jotne的帖子here)是收集lines陣列中文件的所有行。 <element></element>標籤的位置分別保存在i_starti_end中。如果看到<subElement name="removeme"/>found設置爲1(true)。如果found爲真,則將i_end有條件地設置爲0;如果found不正確,則將i_end有條件地設置爲0或者結束元素的行號(數組索引)。如果i_end不爲零,則會打印開始標籤和結束標籤之間的塊。

awk ' 
    { lines[NR] = $0 } 
    /<element>/ { i_start = NR } 
    /<\/element>/ { i_end = found ? 0 : NR; found = 0 } 
    /<subElement name="removeme"\/>/ { found = 1 } 
    i_end { 
    for (i = i_start; i <= i_end; i++) 
     print lines[i] 
    i_end = 0; 
    } 
' file 
+0

謝謝,它工作! – Gusman

3

Regular expressions are certainly the wrong tool to parse XML。你想要一個XML處理工具來刪除節點匹配XPath有一個subElement孩子具有name屬性與價值removeme

使用xmlstarlet//element[subElement[@name="removeme"]]

  • element節點:

    xmlstarlet ed -d '//element[subElement[@name="removeme"]]' << ENDXML 
    <elements> 
        <element> 
         <subElement name="leaveme"/> 
         <subElement name="leaveme"/> 
         <subElement name="leaveme"/> 
        </element> 
        <element> 
         <subElement name="removeme"/> 
         <subElement name="removeme"/> 
         <subElement name="removeme"/> 
        </element> 
        <element> 
         <subElement name="leaveme"/> 
         <subElement name="leaveme"/> 
         <subElement name="leaveme"/> 
        </element> 
    </elements> 
    ENDXML 
    
    <?xml version="1.0"?> 
    <elements> 
        <element> 
        <subElement name="leaveme"/> 
        <subElement name="leaveme"/> 
        <subElement name="leaveme"/> 
        </element> 
        <element> 
        <subElement name="leaveme"/> 
        <subElement name="leaveme"/> 
        <subElement name="leaveme"/> 
        </element> 
    </elements> 
    
+0

試過了,但在os x bash上找不到xmlstarlet,是否有任何替代品? – Gusman

+1

@Gusman您需要安裝[xmlstarlet](http://xmlstar.sourceforge.net/overview.php)。 – ooga

+0

這是正確的做法,但默認情況下,它並未安裝在大多數系統中,並非所有用戶都有權添加其他工具。 – Jotne

1

使用gnu awk你可以做這樣的:

awk -v RS="<element>" '!/removeme/ && NR>1{print RS $0}' file 
<element> 
    <subElement name="leaveme"/> 
    <subElement name="leaveme"/> 
    <subElement name="leaveme"/> 
</element> 

<element> 
    <subElement name="leaveme"/> 
    <subElement name="leaveme"/> 
    <subElement name="leaveme"/> 
</element> 

通過設置RS<element>你告訴awk塊模式下工作,並與<element>
然後!/removeme/告訴awk開始不要用removeme數據打印塊。

0

使用的sed:

sed -n ' 
    /<element>/h 
    /<element>/!H 
    /<\/element>/{g;/<subElement name="removeme"\/>/!p;} 
' file 

/<element>/h命令在初始化匹配與模式空間的內容保留空間。

如果行不匹配<element>,則/<element>/!H命令會將模式空間內容附加到保留空間。

的結束標記和上匹配的/<\/element>/{g;/<subElement name="removeme"\/>/!p}命令測試執行兩個後續命令:

  1. 填充的保持空間被複制到圖案空間。現在,正則表達式將針對包含整個element塊的更新模式空間進行測試。
  2. 正則表達式查找過濾子元素值;在沒有匹配的情況下,模式空間被打印。