আমি কীভাবে কোনও পাঠ্য ফাইলকে একাধিক পাঠ্য ফাইলগুলিতে বিভক্ত করতে পারি?


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। তাদের বিষয়বস্তু নীচে দেওয়া হয়।

প্রবেশ1.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

enter2.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

enter3.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 '/^\[/{match($0, /^\[ (.+?) \]/, k)} {print >k[1]".txt" }' entry.txt

এটি প্রতিটি প্রবেশের শিরোনাম যতক্ষণ না দেখায় ততক্ষণ প্রতিটি প্রবেশের রেখার সংখ্যা নির্বিশেষে কোনও ফাইল আকারের জন্য কাজ করবে [ blahblah blah blah ]। খোলার ঠিক পরে [এবং সমাপ্তির ঠিক আগে জায়গাটি লক্ষ্য করুন ]


ব্যাখ্যা:

awkএবং gawkলাইন দ্বারা একটি ইনপুট ফাইল লাইন পড়ুন। প্রতিটি লাইন পড়ার সাথে সাথে এর বিষয়বস্তুগুলি $0ভেরিয়েবলে সংরক্ষণ করা হয় । এখানে, আমরা gawkবর্গাকার বন্ধনীগুলির মধ্যে যে কোনও কিছুই মেলাতে বলছি এবং এর ম্যাচটি অ্যারেতে সংরক্ষণ করব k

সুতরাং, যতবারই নিয়মিত এক্সপ্রেশনটি মিলে যায়, অর্থাত্ আপনার ফাইলের প্রতিটি শিরোনামের জন্য, কে [1] এর সাথে রেখার মিল রয়েছে have যথা, "এন্ট্রি 1", "এন্ট্রি 2" বা "এন্ট্রি 3" বা "এন্ট্রিএন"।

অবশেষে, আমরা প্রতিটি লাইন মুদ্রণ করি একটি ফাইল হিসাবে <whatever value k currently has>.txt, অর্থাৎ এন্ট্রি 1.txt, entry2.txt ... enterN.txt।

এই পদ্ধতিটি বড় ফাইলগুলির জন্য পার্লের তুলনায় অনেক দ্রুত হবে ।


+1 দুর্দান্ত। আপনার matchপ্রবেশের দরকার নেই : /^\[/ { name=$2 }যথেষ্ট হওয়া উচিত।
থোর

ধন্যবাদ @ থোর বর্ণিত মামলার জন্য আপনার পরামর্শটি সঠিক, তবে এটি ধরে নিয়েছে যে প্রবেশের নামে কখনও কোনও স্থান নেই। এজন্য আমি [ blahblah blah blah ]আমার উত্তরে উদাহরণটি ব্যবহার করেছি।
terdon

আহ স্থান বিচ্ছিন্ন এন্ট্রি সম্পর্কে কিছুটা মিস করেছি। আপনি যেমন তাদের FSযেমন উপযুক্ত করতে পারেন -F '\\[ | \\]'
থোর

@ স্টারডন আমি সত্যিই এই সংক্ষিপ্ত সমাধানগুলি পছন্দ করি, দুর্ভাগ্যক্রমে আমি সাধারণত আমার প্রয়োজনগুলিতে এটিকে সাধারণ করতে ব্যর্থ হই। আপনি আমাকে একটি হাত দিতে পারেন? আমার ফাইলে লাইনগুলি শুরু হয় #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যদিও অ্যারে নম্বরটি খুব ভালভাবে বুঝতে পারছেন না ।
mikuszefski

17

জিএনইউ কোর্টিলস (অ- এমবেডড লিনাক্স, সাইগউইন) এর সিএসপি্লিট সহ :

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

আপনি একটি অতিরিক্ত খালি ফাইল entry0.txt(প্রথম শিরোনামের আগে অংশটি ধারণ করে) দিয়ে শেষ করবেন।

স্ট্যান্ডার্ড সিএসপ্লিটে{*} অনির্দিষ্ট পুনরাবৃত্তিকারী এবং -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

আমি দেখতে পেয়েছি সিএসপি্লিট একবারে কিছুটা কৌতূহলযুক্ত, তবে আমি এই ধরণের জিনিসটি করতে চাইলে অবিশ্বাস্যরূপে কার্যকর।
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} বর্তমান লাইনটি নির্দিষ্ট ফাইলে পুনর্নির্দেশ করে।

মনে রাখবেন যে এই কমলাগার স্ক্রিপ্টের সমস্ত শূন্যস্থান সরিয়ে নেওয়া যেতে পারে, যদি কমপ্যাক্টনেস আপনাকে খুশি করে।

এটিও নোট করুন যে উপরের স্ক্রিপ্টটির সত্যই বিভাগের শিরোনামগুলির চারপাশে স্পেস থাকতে হবে এবং সেগুলির মধ্যে নয়। আপনি যদি বিভাগের শিরোনামগুলির মতো হ্যান্ডেল করতে সক্ষম হতে চান [foo]এবং [ this that ]আপনার আরও কিছুটা কোড প্রয়োজন হয়:

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

sub()স্কয়ার-বন্ধনী-প্লাস-হোয়াইটস্পেসের শীর্ষস্থানীয় এবং পিছনে পিছনের জন্য এটি awk এর ফাংশন ব্যবহার করে । নোট করুন যে প্রতি স্ট্যান্ডার্ড অজানা আচরণ, এটি হোয়াইটস্পেস (ক্ষেত্র বিভাজক) কে একটি একক জায়গায় (অর্থাত্ [ this that ]সংরক্ষণ করা হবে "this that.txt") ভেঙে দেবে । যদি আপনার আউটপুট ফাইলের নামগুলিতে মূল শ্বেতক্ষেত্র বজায় রাখা গুরুত্বপূর্ণ, আপনি এফএস সেট করে পরীক্ষা করতে পারবেন।


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

[রেকর্ড বিভাজক এবং ক্ষেত্র বিভাজক হিসাবে স্থান হিসাবে অ্যাডকে ব্যবহার সম্পর্কে কী । এটি আমাদের সহজেই সেই ফাইলটিতে $0যেখানে ডেটা মুছে ফেলা হবে [এবং ফাইলের নামটি ফাইল হিসাবে রেখে দিতে হবে সেই ডেটা সহজেই দেয় $1। আমাদের তখন কেবল 1 ম রেকর্ডের বিশেষ কেসটি হ্যান্ডেল করতে হবে যা খালি। এটি আমাদের দেয়:

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

2

টেরডনের উত্তরটি আমার পক্ষে কাজ করে তবে আমার গা ছমছমে ব্যবহার করার দরকার ছিল k হাবা ম্যানুয়াল (জন্য অনুসন্ধান 'ম্যাচ (') ব্যাখ্যা করেছেন যে ম্যাচে অ্যারের যুক্তি () একটি হাবা এক্সটেনশান। হয়তো এটি ইনস্টল করুন আপনার awk / nawk / গোবরগনেশ সংস্করণ আপনার Linux উপর নির্ভর করে এবং কিন্তু আমার উবুন্টু মেশিন শুধুমাত্র গোবরগনেশ দৌড়ে 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বিকল্পটি পছন্দ করি তবে বিকল্প হিসাবে এখানে একটি জিএনইউ অ্যাজক সমাধান রয়েছে:

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
এফডাব্লুআইডাব্লু, RTভেরিয়েবল গাক-নির্দিষ্ট হিসাবে উপস্থিত বলে মনে হচ্ছে। এই সমাধানটি আমার পক্ষে ফ্রিবিএসডি-র অ্যাজক ব্যবহার করে কাজ করে না।
ঘোটি

@ ঘোটি: ঠিক আছে, আমার এটি উল্লেখ করা উচিত ছিল। আমি এখন উত্তরে এটি অন্তর্ভুক্ত করেছি। ধন্যবাদ।
থোর
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.