मैं एक पाठ फ़ाइल को कई पाठ फ़ाइलों में कैसे विभाजित कर सकता हूं?


16

मेरे पास एक टेक्स्ट फाइल entry.txtहै, जिसमें निम्नलिखित शामिल हैं:

[ entry1 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3633 3634 3636 3690 3691 3693 3766
3767 3769 4526 4527 4529 4583 4584 4586 4773 4774
4776 5153 5154 5156 5628 5629 5631
[ entry2 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3690 3691 3693 3766 3767 3769 4526
4527 4529 4583 4584 4586 4773 4774 4776 5153 5154
5156 5628 5629 5631
[ entry3 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3690 3691 3693 3766 3767 3769 4241
4242 4244 4526 4527 4529 4583 4584 4586 4773 4774
4776 5153 5154 5156 5495 5496 5498 5628 5629 5631

मैं इसे तीन पाठ फ़ाइलों में विभाजित करना चाहते हैं: entry1.txt, entry2.txt, entry3.txt। उनकी सामग्री इस प्रकार है।

entry1.txt :

[ entry1 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3633 3634 3636 3690 3691 3693 3766
3767 3769 4526 4527 4529 4583 4584 4586 4773 4774
4776 5153 5154 5156 5628 5629 5631

entry2.txt :

[ entry2 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3690 3691 3693 3766 3767 3769 4526
4527 4529 4583 4584 4586 4773 4774 4776 5153 5154
5156 5628 5629 5631

entry3.txt :

[ entry3 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3690 3691 3693 3766 3767 3769 4241
4242 4244 4526 4527 4529 4583 4584 4586 4773 4774
4776 5153 5154 5156 5495 5496 5498 5628 5629 5631

दूसरे शब्दों में, [ चरित्र इंगित करता है कि एक नई फ़ाइल शुरू होनी चाहिए। प्रविष्टियाँ ( [ entry*]जहां *एक पूर्णांक है) हमेशा संख्यात्मक क्रम में होती हैं और लगातार पूर्णांक 1 से एन (मेरी वास्तविक इनपुट फ़ाइल, एन = 200001) से शुरू होती हैं।

क्या कोई तरीका है जो मैं स्वचालित पाठ फ़ाइल को बैश में विभाजित कर सकता हूं? मेरे वास्तविक इनपुट में entry.txtवास्तव में 200,001 प्रविष्टियाँ हैं।

जवाबों:


11

और यहाँ एक अच्छा, सरल, gawk वन-लाइनर है:

$ gawk '/^\[/{match($0, /^\[ (.+?) \]/, k)} {print >k[1]".txt" }' entry.txt

यह किसी भी फ़ाइल आकार के लिए काम करेगा , चाहे प्रत्येक प्रविष्टि में लाइनों की संख्या के बावजूद, जब तक कि प्रत्येक प्रविष्टि शीर्षलेख जैसा दिखता है [ blahblah blah blah ]। उद्घाटन के ठीक बाद [और समापन से ठीक पहले अंतरिक्ष को नोटिस करें ]


व्याख्या:

awkऔर gawkएक इनपुट फ़ाइल लाइन लाइन द्वारा पढ़ें। जैसा कि प्रत्येक पंक्ति पढ़ी जाती है, इसकी सामग्री $0चर में सहेजी जाती है । यहां, हम gawkवर्ग कोष्ठक के भीतर कुछ भी मेल करने के लिए कह रहे हैं , और इसके मैच को सरणी में सहेजें k

इसलिए, हर बार जब नियमित अभिव्यक्ति का मिलान होता है, अर्थात, आपकी फ़ाइल के प्रत्येक शीर्षलेख के लिए, k [1] के पास पंक्ति का मिलान क्षेत्र होगा। अर्थात्, "एंट्री 1", "एंट्री 2" या "एंट्री 3" या "एंट्रीएन"।

अंत में, हम प्रत्येक लाइन को एक फाइल में प्रिंट करते हैं जिसे कहा जाता है <whatever value k currently has>.txt , , प्रविष्टि 1। Txt, entry2.txt ... entryN.txt।

बड़ी फ़ाइलों के लिए पर्ल की तुलना में यह विधि बहुत तेज़ होगी ।


+1 अच्छा। आपको matchप्रवेश की आवश्यकता नहीं है : /^\[/ { name=$2 }पर्याप्त होना चाहिए।
थॉर

धन्यवाद @ ठोर आपका सुझाव वर्णित मामले के लिए सही है, लेकिन यह मानता है कि प्रविष्टि के नाम में कोई जगह नहीं है। इसीलिए मैंने [ blahblah blah blah ]अपने उत्तर में उदाहरण का उपयोग किया ।
terdon

आह मैं अंतरिक्ष अलग प्रविष्टियों के बारे में थोड़ा याद किया। आप उन लोगों को भी समायोजित कर सकते हैं FS, जैसे -F '\\[ | \\]'
थोर

@terdon मैं वास्तव में इस छोटे से समाधान को पसंद करता हूं, दुर्भाग्य से मैं आमतौर पर अपनी आवश्यकताओं के लिए उन्हें सामान्य करने में विफल रहता हूं। क्या आप मेरी मदद कर सकते हैं? मेरी फ़ाइल में रेखाएँ हैं #S x, जहाँ x एक 1, 2 या 3 अंकों की संख्या है। बस उन्हें x.dat में सहेजना पर्याप्त होगा। मैंने कोशिश की: gawk '/^#S/{match($0, / [0-9]* /, k)} {print >k[1]".dat" }' myFile.txtऔर उस के कुछ रूपांतर।
मिकुसेज़फ़स्की

समझ गया यह gawk '/^#S/{match($0, /^#S (\s+?)([0-9]+)(\s+?)/, k)} {print >k[2]".txt" }' test.txtतरकीब। 2हालांकि, सरणी संख्या को बहुत अच्छी तरह से न समझें ।
मिकुस्सेफ़स्की

17

GNU कोरुटिल्स (गैर-एम्बेडेड लिनक्स, सिग्विन) से सीएसपीलिट के साथ :

csplit -f entry -b '%d.txt' entry.txt '/^\[ .* \]$/' '{*}'

आप एक अतिरिक्त खाली फ़ाइल के साथ समाप्त करेंगे entry0.txt (पहले हेडर से पहले वाला हिस्सा) के ।

मानक csplit में {*}अनिश्चित पुनरावर्तक और -bप्रत्यय प्रारूप को निर्दिष्ट करने के विकल्प का अभाव होता है, इसलिए अन्य प्रणालियों पर आपको पहले खंडों की संख्या गिननी होगी और बाद में आउटपुट फ़ाइलों का नाम बदलना होगा।

csplit -f entry -n 9 entry.txt '/^\[ .* \]$/' "{$(egrep -c '^'\[ .* \]$' <entry.txt)}"
for x in entry?????????; do
  y=$((1$x - 1000000000))
  mv "entry$x" "entry$y.txt"
done

मुझे लगता है कि csplit थोड़ी देर में एक बार थोड़ा विचित्र है, लेकिन अविश्वसनीय रूप से उपयोगी है जब मैं इस तरह का काम करना चाहता हूं।
ixtmixilix

10

पर्ल में इसे बहुत सरल बनाया जा सकता है:

perl -ne 'open(F, ">", ($1).".txt") if /\[ (entry\d+) \]/; print F;' file

9

यहाँ एक छोटी ओके लाइनर है:

awk '/^\[/ {ofn=$2 ".txt"} ofn {print > ofn}' input.txt

यह कैसे काम करता है?

  • /^\[/ मैचों को एक बाएं वर्ग ब्रैकेट के साथ शुरू होता है, और
  • {ofn=$2 ".txt"}हमारे आउटपुट फ़ाइल नाम के रूप में दूसरे सफेद-स्पेस-सीमांकित शब्द के लिए एक चर सेट करता है। फिर,
  • ofn एक ऐसी स्थिति है जो चर के सेट होने पर सत्य का मूल्यांकन करती है (इस प्रकार आपके पहले हेडर को अनदेखा करने से पहले लाइनें पैदा करती हैं)
  • {print > ofn} वर्तमान लाइन को निर्दिष्ट फ़ाइल पर पुनर्निर्देशित करता है।

ध्यान दें कि इस awk स्क्रिप्ट में सभी रिक्त स्थान को हटाया जा सकता है, यदि कॉम्पैक्टनेस आपको खुश करती है।

यह भी ध्यान दें कि उपरोक्त स्क्रिप्ट को वास्तव में अनुभाग शीर्षकों की आवश्यकता है कि उनके आसपास रिक्त स्थान हो और उनके भीतर नहीं। आप जैसे अनुभाग शीर्षलेख को संभालने में सक्षम होना चाहते थे, तो [foo]और [ this that ], आप कभी तो थोड़ा और अधिक कोड आवश्यकता होगी:

awk '/^\[/ {sub(/^\[ */,""); sub(/ *\] *$/,""); ofn=$0 ".txt"} ofn {print > ofn}' input.txt

यह sub()स्क्वायर-ब्रैकेट्स-प्लस-व्हाट्सएप को अग्रणी और पीछे करने के लिए awk के फ़ंक्शन का उपयोग करता है । ध्यान दें कि मानक awk व्यवहार के अनुसार, यह व्हाट्सएप (क्षेत्र विभाजक) को एक ही स्थान में ध्वस्त कर देगा (यानी [ this that ]सहेजा गया है "this that.txt")। यदि आपके आउटपुट फ़ाइलनाम में मूल व्हाट्सएप को बनाए रखना महत्वपूर्ण है, तो आप FS सेट करके प्रयोग कर सकते हैं।


2

यह अजगर के रूप में कमांड लाइन से किया जा सकता है:

paddy$ python3 -c 'out=0
> with open("entry.txt") as f: 
>   for line in f:
>     if line[0] == "[":
>       if out: out.close()
>       out = open(line.split()[1] + ".txt", "w")
>     else: out.write(line)'

2

यह कुछ हद तक कच्चा है, लेकिन इसे आसानी से समझा जा सकता है: grep -l '[ entry ]' FILENAME[प्रविष्टि] पर विभाजित करने के लिए लाइन नंबर प्राप्त करने के लिए उपयोग करें। सही टुकड़े प्राप्त करने के लिए सिर और पूंछ के संयोजन का उपयोग करें।

जैसा मैंने कहा; यह सुंदर नहीं है, लेकिन समझना आसान है।


2

क्षेत्र विभाजक के रूप में [रिकॉर्ड विभाजक और अंतरिक्ष के रूप में awk का उपयोग करने के बारे में क्या । यह हमें आसानी से डेटा को फ़ाइल में डालने के लिए देता है, $0जहाँ उसे हटाए गए अग्रणी [और फ़ाइल नाम को वापस रखना पड़ता है $1। हमें केवल 1 रिकॉर्ड के विशेष मामले को संभालना है जो खाली है। यह हमें देता है:

awk -v "RS=[" -F " " 'NF != 0 {print "[" $0 > $1}' entry.txt

2

टेर्डन का जवाब मेरे लिए काम करता है, लेकिन मुझे गोक का इस्तेमाल करने की जरूरत है, जागने की नहीं। Gawk पुस्तिका (के लिए खोज 'मैच (') बताते हैं कि मैच में सरणी तर्क () एक gawk विस्तार है। हो सकता है कि इसे स्थापित अपने awk / nawk / gawk संस्करणों अपने लिनक्स पर निर्भर करता है और लेकिन मेरी Ubuntu मशीन केवल gawk दौड़ा terdon उत्तम पर का जवाब:

$ gawk '{if(match($0, /^\[ (.+?) \]/, k)){name=k[1]}} {print >name".txt" }' entry.txt

1

यहाँ एक पर्ल समाधान है। यह स्क्रिप्ट [ entryN ]लाइनों का पता लगाती है और आउटपुट फाइल को उसी के अनुसार बदल देती है, लेकिन प्रत्येक अनुभाग में डेटा को मान्य, पार्स या संसाधित नहीं करती है, यह सिर्फ आउटपुट लाइन को आउटपुट फाइल में प्रिंट करती है।

#! /usr/bin/perl 

# default output file is /dev/null - i.e. dump any input before
# the first [ entryN ] line.

$outfile='/dev/null';
open(OUTFILE,">",$outfile) || die "couldn't open $outfile: $!";

while(<>) {
  # uncomment next two lines to optionally remove comments (starting with
  # '#') and skip blank lines.  Also removes leading and trailing
  # whitespace from each line.
  # s/#.*|^\s*|\s*$//g;
  # next if (/^$/)

  # if line begins with '[', extract the filename
  if (m/^\[/) {
    (undef,$outfile,undef) = split ;
    close(OUTFILE);
    open(OUTFILE,">","$outfile.txt") || die "couldn't open $outfile.txt: $!";
  } else {
    print OUTFILE;
  }
}
close(OUTFILE);

1

हाय मैं अपनी समस्या को हल करने के लिए रूबी का उपयोग करके यह सरल स्क्रिप्ट लिखी

#!ruby
# File Name: split.rb

fout = nil

while STDIN.gets
  line = $_
  if line.start_with? '['
    fout.close if fout
    fname = line.split(' ')[1] + '.txt'
    fout = File.new fname,'w'
  end
  fout.write line if fout
end

fout.close if fout

आप इसे इस तरह से उपयोग कर सकते हैं:

ruby split.rb < entry.txt

मैं यह परीक्षण किया है, और यह ठीक काम करता है ..


1

मैं csplitविकल्प पसंद करता हूं लेकिन एक विकल्प के रूप में यहां एक GNU awk समाधान है:

parse.awk

BEGIN { 
  RS="\\[ entry[0-9]+ \\]\n"  # Record separator
  ORS=""                      # Reduce whitespace on output
}
NR == 1 { f=RT }              # Entries are of-by-one relative to matched RS
NR  > 1 {
  split(f, a, " ")            # Assuming entries do not have spaces 
  print f  > a[2] ".txt"      # a[2] now holds the bare entry name
  print   >> a[2] ".txt"
  f = RT                      # Remember next entry name
}

इसे इस तरह चलाएं:

gawk -f parse.awk entry.txt

1
FWIW, RTचर विशिष्ट-विशिष्ट प्रतीत होता है। यह समाधान मेरे लिए FreeBSD के awk का उपयोग करके काम नहीं करता है।
घोटी

@ घाघी: ठीक है, मुझे इसका उल्लेख करना चाहिए था। मैंने उस उत्तर में अभी शामिल किया है। धन्यवाद।
थोर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.