2011-09-08 46 views
2

我有成千上萬的文本文件,我已經導入了包含一段我想刪除的文本。如何使用sed/awk從文件中刪除文本塊(模式)

它不只是一個文本塊,而是一個模式。

<!-- 
# Translator(s): 
# 
# username1 <email1> 
# username2 <email2> 
# usernameN <emailN> 
# 
--> 

該塊如果出現,將有一個或多個用戶列出他們的電子郵件地址。

回答

0

對於此任務,您需要向前看,這通常是使用解析器完成的。

另一種解決方案,但不是非常有效的將是:

sed "s/-->/&\n/;s/<!--/\n&/" file | awk 'BEGIN {RS = "";FS = "\n"}/username/{print}' 

HTH克里斯

+0

爲什麼你認爲這是低效? IT目前的稀缺資源是程序員時間,而不是計算機效率。帶有兩個易於理解的陳述的單行看起來對我來說非常有效;解析器解決方案會是什麼樣子;-)?祝你好運! – shellter

+0

你說得對。這個解決方案將是我的第一次嘗試。但是對於數千個文件來說,這可能不夠高效。 – Chris

+0

不夠公平,我忽略了數千個文件的需求。我會說,如果這是一次成千上萬的文件需求,那麼你的解決方案仍然足夠好,(在for循環內)。如果每天有數千個文件,那麼解析器解決方案可能會很有用。 @armenzg:你的運行時間有多關鍵?附:克里斯:我爲你的答案做了一個贊成,但我沒有看到1(我確實看到一個黃色的箭頭)。也許它會在稍後顯示。祝你們好運。 – shellter

-1

這裏是我的解決方案,如果我理解正確你的問題。保存到以下一個名爲remove_blocks.awk:

# See the beginning of the block, mark it 
/<!--/ { 
    state = "block_started" 
} 

# At the end of the block, if the block does not contain email, print 
# out the whole block. 
/^-->/ { 
    if (!block_contains_user_email) { 
     for (i = 0; i < count; i++) { 
      print saved_line[i]; 
     } 
     print 
    } 

    count = 0 
    block_contains_user_email = 0 
    state = "" 
    next 
} 

# Encounter a block: save the lines and wait until the end of the block 
# to decide if we should print it out 
state == "block_started" { 
    saved_line[count++] = $0 
    if (NF>=3 && $3 ~ /@/) { 
     block_contains_user_email = 1 
    } 
    next 
} 

# For everything else, print the line 
1 

假設您的文本文件是data.txt中(或多個文件,對於這個問題):

awk -f remove_blocks.awk data.txt 

上述命令將打印將文本文件中的所有內容減去包含用戶電子郵件的塊。

0
perl -i.orig -00 -pe 's/<!--\s+#\s*Translator.*?\s-->//gs' file1 file2 file3 
+0

-1這將刪除以#Translator開頭的任何註釋塊。例如: <! - #譯者 這是一條評論 - > – dogbane

+1

@Dogbane:爲什麼會這樣:是不是被要求的確切任務?你的投訴是什麼? – tchrist

+0

首先它應該匹配「譯者:」。其次,您的解決方案不考慮用戶名和他們的電子郵件地址。 – dogbane

0

這SED解決方案可能的工作:

sed '/^<!--/,/^-->/{/^<!--/{h;d};H;/^-->/{x;/^<!--\n# Translator(s):\n#\(\n# [^<]*<email[0-9]\+>\)\+\n#\n-->$/!p};d}' file 
0

我有完成任務的代碼非常少排另一個小awk程序。它可以用來從文件中刪除文本的模式。開始以及停止regexp可以設置。

# This block is a range pattern and captures all lines between(and including) 
# the start '<!--' to the end '-->' and stores the content in record $0. 
# Record $0 contains every line in the range pattern. 
# awk -f remove_email.awk yourfile 

# The if statement is not needed to accomplish the task, but may be useful. 
# It says - if the range patterns in $0 contains a '@' then it will print 
# the string "Found an email..." if uncommented. 

# command 'next' will discard the content of the current record and search 
# for the next record. 
# At the same time the awk program begins from the beginning. 


/<!--/, /-->/ { 
    #if($0 ~ /@/){ 
     # print "Found an email and removed that!" 
    #} 
next 
} 

# This line prints the body of the file to standard output - if not captured in 
# the block above. 
1 { 
    print 
} 

保存在 'remove_email.awk' 的代碼和運行它: AWK -f remove_email.awk yourfile