從a文件判斷是否刪除b文件中的行(sed示例)


bash&shell系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.html


test.xml文件很大,內容結構如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<url>
    <loc>http://www.u1cat.net/index.php?ctl=register</loc>
    <lastmod>2016-10-31</lastmod>
    <changefreq>always</changefreq>
    <priority>aaa</priority>
</url>

<url>
    <loc>http://www.u2bat.cc/index.php?ctl=register</loc>
    <lastmod>2015-11-18</lastmod>
    <changefreq>always</changefreq>
    <priority>bbb</priority>
</url>
<url>
    <loc>http://www.u3bat.cc/index.php?ctl=register</loc>
    <lastmod>2015-11-18</lastmod>
    <changefreq>always</changefreq>
    <priority>ccc</priority>
</url>
<url>
    <loc>http://www.u4bat.cc/index.php?ctl=register</loc>
    <lastmod>2015-11-18</lastmod>
    <changefreq>always</changefreq>
    <priority>ddd</priority>
</url>
<url>
    <loc>http://www.u5bat.cc/index.php?ctl=register</loc>
    <lastmod>2015-11-18</lastmod>
    <changefreq>always</changefreq>
    <priority>ddd</priority>
</url>
......

list.txt文件較小,內容如下:

bbb
xxx
yyy
ccc

需求是,如果<url>...</url>中間包含了list.txt文件中的某一行,則刪除這個<url>...</url>

在這里需要說明下sed的局限性:
(1).sed處理輸入流是一次性的,只要某行被sed讀取了,就一定不會再讀取。因此,讀取到某滿足匹配要求的行時,無法定位到它前面的某行、某幾行。
(2).sed自身沒有顯式的循環結構,例如while、for、until。但是通過某些功能的結合,可以隱式地實現循環。據我總結,只有標簽跳轉和"NDP"才能實現這種隱式意義上的循環。
(3).sed和system命令交互的局限性非常大。只有e命令和s命令的e修飾符才能執行system中的命令。
正是這3個局限性,導致sed實現上面的需求非常困難。

以下是一種效率非常高的方法:只讀取一次test.xml和list.txt文件,並在每次讀取到<url>...</url>的時候判斷是否需要刪除這一段。

創建sed腳本文件a.sed:

#!/usr/bin/sed -nf

\%<url>%!p
1{s/.*/cat list.txt/e;h}

\%<url>%{
N;N;N;N;N;G;
\%<priority>(.*)</priority>.*\1.*%d } s%</url>.*%</url>%p

執行sed:

sed -rn -f a.sed test.xml

由於上面示例文件中<priority>bbb</priority><priority>ccc</priority>的bbb、ccc存在於list.txt文件中,因此這兩個<url>...</url>段落要刪除。執行結果為:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<url>
    <loc>http://www.u1cat.net/index.php?ctl=register</loc>
    <lastmod>2016-10-31</lastmod>
    <changefreq>always</changefreq>
    <priority>aaa</priority>
</url>

<url>
    <loc>http://www.u4bat.cc/index.php?ctl=register</loc>
    <lastmod>2015-11-18</lastmod>
    <changefreq>always</changefreq>
    <priority>ddd</priority>
</url>
<url>
    <loc>http://www.u5bat.cc/index.php?ctl=register</loc>
    <lastmod>2015-11-18</lastmod>
    <changefreq>always</changefreq>
    <priority>ddd</priority>
</url>

思路大致為:

  • (1).一開始就通過sed的e命令將list.txt文件讀取到pattern space空間,並保存到hold space。
  • (2).每讀取到<url>的時候就繼續讀取后面5行,正好讀到</url>。
  • (3).讀完了后,把hold space中的內容追加回pattern space,並從XXXXX開始判斷后面是否還有XXXXX,如果有就直接刪除pattern space,否則就將追加回pattern space的list.txt內容刪除,最后輸出。
  • (4).這樣的執行方式,只需讀取一次test.xml和list.txt文件,效率很高。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM