2011-12-17 13 views
33

पर आधारित लिनक्स में एक फ़ाइल को विभाजित करना मेरे पास लगभग 400 एमबी का ईमेल डंप है। मैं इसे .txt फ़ाइलों में विभाजित करना चाहता हूं, जिसमें प्रत्येक फ़ाइल में एक मेल शामिल है। प्रत्येक ई-मेल मानक HTML शीर्षलेख के साथ शुरू होता है जो डॉक्ट टाइप निर्दिष्ट करता है।सामग्री

इसका मतलब है कि मुझे उपर्युक्त शीर्षलेख के आधार पर अपनी फ़ाइलों को विभाजित करना होगा। मैं लिनक्स में इसके बारे में कैसे जा सकता हूं?

+0

क्या वाकई यह एक ईमेल डंप है? तुम्हारा मतलब है कि आपके पास कोई मेल हेडर नहीं है? और आप "मानक HTML शीर्षलेख को निर्दिष्ट करते हुए" क्या कहते हैं? – fge

+0

" इसके बाद पूरे ई-मेल का पालन किया जाता है! – Greenhorn

उत्तर

54

आप एक mail.txt

$ cat mail.txt 
<html> 
    mail A 
</html> 

<html> 
    mail B 
</html> 

<html> 
    mail C 
</html> 

रन csplit<html>

$ csplit mail.txt '/^<html>$/' '{*}' 

- mail.txt => input file 
- /^<html>$/ => pattern match every `<html>` line 
- {*}   => repeat the previous pattern as many times as possible 

जांच उत्पादन

द्वारा विभाजित करने के लिए है, तो
$ ls 
mail.txt xx00 xx01 xx02 xx03 

आप awk

$ awk '/<html>/{filename=NR".txt"}; {print >filename}' mail.txt 
$ ls 
1.txt 5.txt 9.txt mail.txt 
+0

Am डर! मैं भी ऐसा ही किया और xx00 और स्पष्ट रूप से मेल एक $ ls mail.txt किया .txt xx00 0 जैसा ही थाकोई फिक्स? – Greenhorn

+0

@ रामप्रकाश मेरा 'csplit' का ver' 8.5' है। हो सकता है कि आपके पास '{*}' नहीं है जो पैटर्न दोहराना है। कृपया मैनपेज की जांच करें। मैं बस 'awk' समाधान जोड़ें। आप इसे आज़मा सकते हैं। – kev

+0

Awk काम किया :) बहुत बहुत धन्यवाद! – Greenhorn

1

यह कुछ perl "जादू" के साथ करने योग्य है ... कई लोग इस बदसूरत को बुलाएंगे लेकिन यहां जाता है।

चाल आप क्या चाहते हैं के साथ $/ की जगह और अपने इनपुट पढ़ते हैं, इस तरह के रूप के लिए है:

#!/usr/bin/perl -W 
use strict; 
my $i = 1; 

$/ = <<EOF; 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head> <xmeta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type"> 
EOF 

open INPUT, "/path/to/inputfile" or die; 

while (my $mail = <INPUT>) { 
    $mail = substr($mail, 0, index($mail, $/)); 
    open OUTPUT, ">/path/to/emailfile." . $i . ".txt" or die; 
    $i++; 
    print OUTPUT $mail; 
    close OUTPUT; 
} 

संपादित करें: तय, मैं हमेशा भूल जाते हैं कि $/ इनपुट में शामिल है। साथ ही, पहली फ़ाइल हमेशा खाली होगी, लेकिन फिर इसे आसानी से संभाला जा सकता है।

1

मैं fge से सहमत हूं। perl के साथ यह बहुत आसान होगा। आप कुछ इस तरह की कोशिश कर सकते हैं -

#!/usr/bin/perl 

undef $/; 
$_ = <>; 
$n = 0; 

for $match (split(/(?=HEADER_FORMAT)/)) { 
     open(O, '>mail' . ++$n); 
     print O $match; 
     close(O); 
} 

अपने हैडर प्रकार के साथ HEADER_FORMAT बदलें।

+0

हाँ, एक सकारात्मक लुकहेड अच्छी तरह से काम करेगा, खासकर जब से हेडर में कोई मेटाएक्टेक्टर नहीं होता है। आप 'qr // ' विभाजन regex बनाने के लिए। – fge

4

csplit कार्यक्रम सुंदर ढंग से अपनी समस्या का हल:

csplit '/<!DOCTYPE.*/' $FILE 
+1

तर्क गलत क्रम में हैं और के रूप में इरादा पुनरावृत्ति वास्तव में क्या करने के लिए याद आ रही है। – qwertzguy

2

csplit में ऐसा चाहते हैं इस समस्या का सबसे अच्छा समाधान है। बस सोचा कि मैं यह दिखाने के लिए एक बैश-समाधान पोस्ट करूंगा कि इस कार्य पर पर्ल जाने की कोई आवश्यकता नहीं है:

#!/usr/bin/bash 

MAIL='mail'  # path to huge mail-file 

#get linenumbers for all headers 
line_no=$(grep -n html $MAIL | cut -d: -f1) 

read -a LINES<<< $line_no 

file=0 
for i in $(seq 0 2 ${#LINES[@]}); do 
    start=${LINES[i]} 
    end=$((${LINES[i+1]}-1)) 
    echo $start, $end 
    sed -n "${start},${end}p" $MAIL > ${MAIL}${file}.txt 
    file=$((file+1)) 
done 
संबंधित मुद्दे