ডিলিমিটারের ভিত্তিতে এক ফাইলকে একাধিক ফাইলগুলিতে বিভক্ত করুন


88

-|প্রতিটি বিভাগের পরে ডিলিমিটার সহ আমার একটি ফাইল আছে ... ইউনিক্স ব্যবহার করে প্রতিটি বিভাগের জন্য পৃথক ফাইল তৈরি করা দরকার।

ইনপুট ফাইলের উদাহরণ

wertretr
ewretrtret
1212132323
000232
-|
ereteertetet
232434234
erewesdfsfsfs
0234342343
-|
jdhg3875jdfsgfd
sjdhfdbfjds
347674657435
-|

ফাইল 1-এ প্রত্যাশিত ফলাফল

wertretr
ewretrtret
1212132323
000232
-|

ফাইল 2-এ প্রত্যাশিত ফলাফল

ereteertetet
232434234
erewesdfsfsfs
0234342343
-|

ফাইল 3-এ প্রত্যাশিত ফলাফল

jdhg3875jdfsgfd
sjdhfdbfjds
347674657435
-|

4
আপনি কি কোনও প্রোগ্রাম লিখছেন বা কমান্ড লাইন ইউটিলিটিগুলি ব্যবহার করে আপনি এটি করতে চান?
rkyser

4
কমান্ড লাইন ইউটিলিটিগুলি ব্যবহার করা পছন্দনীয় হবে ..
ব্যবহারকারীর 1499178

আপনি awk ব্যবহার করতে পারেন, এটি করার জন্য 3 বা 4 লাইনের প্রোগ্রামটি লেখা সহজ হবে। দুর্ভাগ্যক্রমে আমি অনুশীলনের বাইরে আছি।
ctrl-alt-delor

উত্তর:


98

একটি ওয়ান লাইনার, কোনও প্রোগ্রামিং নেই। (রেগএক্সপ্যাক ইত্যাদি ব্যতীত)

csplit --digits=2  --quiet --prefix=outfile infile "/-|/+1" "{*}"

পরীক্ষিত: csplit (GNU coreutils) 8.30

অ্যাপল ম্যাক ব্যবহার সম্পর্কে নোটস

"ওএস এক্স ব্যবহারকারীদের জন্য, নোট করুন যে csplitওএসের সাথে এর সংস্করণটি কাজ করে না core আপনি কোর্টিলগুলিতে (হোমব্রিউয়ের মাধ্যমে ইনস্টলযোগ্য) সংস্করণ চাইবেন, যাকে বলা হয় gcsplit" " - @ ড্যানিয়াল

"কেবল যোগ করার জন্য, আপনি ওএস এক্সের কাজ করার জন্য সংস্করণটি পেতে পারেন (কমপক্ষে হাই সিয়েরার সাথে) You আপনাকে আরোগুলিগুলিকে কিছুটা টুইঙ্ক csplit -k -f=outfile infile "/-\|/+1" "{3}"করতে হবে Features যে বৈশিষ্ট্যগুলি কাজ করে বলে মনে হয় না সেগুলি হ'ল "{*}", আমি নির্দিষ্ট করেছিলাম বিভাজক সংখ্যা, যোগ করা প্রয়োজন -kসব outfiles মোছার এটা এড়ানোর জন্য যদি এটি একটি চূড়ান্ত বিভাজক খুঁজে পাচ্ছি না। এছাড়াও আপনি চাইলে --digits, আপনি ব্যবহার করতে হবে -nপরিবর্তে। " - @ পেবল


31
@ zb226 আমি দীর্ঘক্ষণ এটি করেছি, যাতে কোনও ব্যাখ্যা দেওয়ার দরকার পড়ে না।
ctrl-alt-delor

4
আমি যুক্ত করার পরামর্শ দিই --elide-empty-files, অন্যথায় শেষে একটি খালি ফাইল থাকবে।
luator

8
ওএস এক্স ব্যবহারকারীদের জন্য নোট করুন যে ওএসের সাথে আসা সিএসপি্লির সংস্করণটি কাজ করে না। আপনি কোর্টিলগুলিতে (হোমব্রিউয়ের মাধ্যমে ইনস্টলযোগ্য) সংস্করণটি চাইবেন, যাকে gcsplit বলা হয়
ড্যানিয়েল

10
যারা প্যারামিটারগুলির অর্থ কী তা অবাক করে: --digits=2আউটপুট ফাইলগুলি সংখ্যার জন্য ব্যবহৃত অঙ্কগুলির সংখ্যা নিয়ন্ত্রণ করে (2 আমার পক্ষে ডিফল্ট, সুতরাং প্রয়োজনীয় নয়)। --quietআউটপুট দমন করে (এটিও সত্যই প্রয়োজনীয় নয় বা এখানে জিজ্ঞাসা করা হয়েছিল)। --prefixআউটপুট ফাইলগুলির উপসর্গ নির্দিষ্ট করে (ডিফল্টটি এক্সএক্সএক্স)। সুতরাং আপনি সমস্ত প্যারামিটারগুলি এড়িয়ে যেতে পারেন এবং আউটপুট ফাইলগুলির মতো পাবেন xx12
ক্রিস্টোফার কে।

4
কেবল যোগ করতে, আপনি ওএস এক্স এর কাজ করার জন্য সংস্করণটি পেতে পারেন (কমপক্ষে হাই সিয়েরার সাথে)। আপনার কেবল আরোগুলিটি কিছুটা সামলানো দরকার csplit -k -f=outfile infile "/-\|/+1" "{3}"। যে বৈশিষ্ট্যগুলি কাজ করে বলে মনে হয় না সেগুলি "{*}"হ'ল, আমাকে পৃথককারী সংখ্যার বিষয়ে সুনির্দিষ্ট হতে হয়েছিল এবং -kএটির চূড়ান্ত বিভাজকটি খুঁজে না পাওয়া গেলে এটি সমস্ত আউটফাইলে মুছে ফেলা এড়াতে যোগ করার দরকার ছিল । এছাড়াও যদি আপনি চান তবে আপনার পরিবর্তে --digitsব্যবহার -nকরা উচিত।
পেব্ল

39
awk '{f="file" NR; print $0 " -|"> f}' RS='-\\|'  input-file

ব্যাখ্যা (সম্পাদিত):

RSএটি রেকর্ড পৃথককারী এবং এই সমাধানটিতে একটি gnu অজ এক্সটেনশন ব্যবহার করা হয় যা এটি একের বেশি অক্ষরের হতে দেয়। NRরেকর্ড নম্বর।

মুদ্রণ বিবৃতিটি " -|"একটি ফাইলের পরে একটি রেকর্ড মুদ্রণ করে যার নামে রেকর্ড নম্বর থাকে।


4
RSএটি রেকর্ড পৃথককারী এবং এই সমাধানটিতে একটি gnu অজ এক্সটেনশন ব্যবহার করা হয় যা এটি একের বেশি অক্ষরের হতে দেয়। এনআর হ'ল রেকর্ড নম্বর। মুদ্রণ বিবৃতি "- |" এর পরে একটি রেকর্ড মুদ্রণ করে একটি ফাইল যা তার নামে রেকর্ড নম্বর রয়েছে।
উইলিয়াম পার্সেল

4
@rzetterbeg বড় ফাইলগুলির সাথে এটি ভালভাবে কাজ করা উচিত। awk ফাইলটি একবারে একটি রেকর্ড প্রক্রিয়া করে, তাই এটি কেবল এটির যতটা প্রয়োজন পড়বে। রেকর্ড পৃথককারীটির প্রথম উপস্থিতি যদি ফাইলটিতে খুব দেরীতে দেখা যায় তবে এটি একটি স্মৃতি ক্রাচ হতে পারে কারণ একটি সম্পূর্ণ রেকর্ড অবশ্যই মেমরির সাথে মাপসই করা উচিত। এছাড়াও, নোট করুন যে আরএসে একাধিক অক্ষর ব্যবহার করা স্ট্যান্ডার্ড অ্যাজক নয়, তবে এটি gnu awk এ কাজ করবে।
উইলিয়াম পার্সেল

4
আমার জন্য এটি 31.328 সেকেন্ডে 3.3 জিবি বিভক্ত হয়েছে
ক্লিয়ানকোড

4
@ সিসিএফ ফাইলের নামটি ডান দিকে কেবল স্ট্রিং >, সুতরাং আপনি এটি পছন্দমত তৈরি করতে পারেন। যেমন,print $0 "-|" > "file" NR ".txt"
উইলিয়াম পার্সেল

4
@ গ্রাশ এটি সংস্করণ নির্ভর। আপনি করতে পারেনawk '{f="file" NR; print $0 " -|" > f}'
উইলিয়াম পার্সেল

7

ডেবিয়ান আছে csplit, তবে আমি জানি না যে এটি সমস্ত / বেশিরভাগ / অন্যান্য বিতরণে সাধারণ। যদি তা না হয় তবে উত্সটি সন্ধান এবং এটি সংকলন করা খুব কঠিন হওয়া উচিত নয় ...


4
আমি রাজী. আমার ডেবিয়ান বাক্স বলে যে সিএসপ্লিটটি গ্নু কোর্টিলসের অংশ। সুতরাং যে কোনও Gnu অপারেটিং সিস্টেম যেমন সমস্ত Gnu / লিনাক্স ডিস্ট্রোগুলিতে এটি থাকবে। উইকিপিডিয়াতে সিএসপ্লিট পৃষ্ঠায় 'দ্য সিঙ্গলাল ইউনিক্স স্পেসিফিকেশন, ইস্যু 7' উল্লেখ করেছে, সুতরাং আমি সন্দেহ করি যে আপনি এটি পেয়েছেন।
ctrl-alt-delor

4
যেহেতু csplitপসিক্সে রয়েছে তাই আমি আশা করব যে এটি মূলত সমস্ত ইউনিক্সের মতো সিস্টেমে উপলব্ধ হবে।
জোনাথন লেফলার

4
যদিও সিএসপি্লিটটি পইআইএসএক্স, সমস্যাটি মনে হচ্ছে (এটি আমার সামনে বসে উবুন্টু সিস্টেমে এটি পরীক্ষা করে দেখানো হচ্ছে) এটি আরও আধুনিক রেজেক্স সিনট্যাক্সটি ব্যবহার করার কোনও সুস্পষ্ট উপায় নেই। তুলনা: csplit --prefix gold-data - "/^==*$/বনাম csplit --prefix gold-data - "/^=+$/। কমপক্ষে জিএনইউ গ্রেপ রয়েছে -e
new123456

5

আমি কিছুটা আলাদা সমস্যা সমাধান করেছি, যেখানে ফাইলটির নামের সাথে একটি লাইন রয়েছে যেখানে নিম্নলিখিত পাঠ্যটি যাওয়া উচিত। এই পার্ল কোডটি আমার পক্ষে কৌতুক করে:

#!/path/to/perl -w

#comment the line below for UNIX systems
use Win32::Clipboard;

# Get command line flags

#print ($#ARGV, "\n");
if($#ARGV == 0) {
    print STDERR "usage: ncsplit.pl --mff -- filename.txt [...] \n\nNote that no space is allowed between the '--' and the related parameter.\n\nThe mff is found on a line followed by a filename.  All of the contents of filename.txt are written to that file until another mff is found.\n";
    exit;
}

# this package sets the ARGV count variable to -1;

use Getopt::Long;
my $mff = "";
GetOptions('mff' => \$mff);

# set a default $mff variable
if ($mff eq "") {$mff = "-#-"};
print ("using file switch=", $mff, "\n\n");

while($_ = shift @ARGV) {
    if(-f "$_") {
    push @filelist, $_;
    } 
}

# Could be more than one file name on the command line, 
# but this version throws away the subsequent ones.

$readfile = $filelist[0];

open SOURCEFILE, "<$readfile" or die "File not found...\n\n";
#print SOURCEFILE;

while (<SOURCEFILE>) {
  /^$mff (.*$)/o;
    $outname = $1;
#   print $outname;
#   print "right is: $1 \n";

if (/^$mff /) {

    open OUTFILE, ">$outname" ;
    print "opened $outname\n";
    }
    else {print OUTFILE "$_"};
  }

আপনি দয়া করে ব্যাখ্যা করতে পারেন কেন এই কোডটি কাজ করে? আপনি এখানে যা বর্ণনা করেছেন তার সাথে আমারও একই অবস্থা রয়েছে - প্রয়োজনীয় আউটপুট ফাইলের নামগুলি ফাইলের মধ্যে এম্বেড করা হয়। তবে আমি কোনও নিয়মিত পার্ল ব্যবহারকারী নই তাই এই কোডটি বেশ বোঝা যায় না।
শিরি

আসল গরুর মাংস চূড়ান্ত whileলুপে রয়েছে। যদি এটি mffলাইনের শুরুতে রেজেক্সটি সন্ধান করে তবে এটি বাকী রেখাকে ফাইলের নাম হিসাবে খোলার জন্য এবং লেখার জন্য ব্যবহার করে। এটি কখনই কিছুই বন্ধ করে না তাই কয়েক ডজন পরে ফাইল হ্যান্ডলগুলি শেষ হয়ে যাবে।
ট্রিপলি

স্ক্রিপ্টটি আসলে চূড়ান্ত whileলুপের আগে বেশিরভাগ কোড সরিয়ে এবং while (<>)
স্নায়ু

4

নিম্নলিখিত কমান্ডটি আমার পক্ষে কাজ করে। আশা করি এটা সাহায্য করবে.

awk 'BEGIN{file = 0; filename = "output_" file ".txt"}
    /-|/ {getline; file ++; filename = "output_" file ".txt"}
    {print $0 > filename}' input

4
এটি সাধারণত কয়েক ডজন ফাইলের পরে ফাইল হ্যান্ডলগুলি শেষ হয়ে যাবে। সমাধানটি হ'ল স্পষ্টভাবে closeপুরানো ফাইলটি যখন আপনি একটি নতুন শুরু করবেন।
ট্রিপলি

@ ট্রিপলি আপনি কীভাবে এটি বন্ধ করবেন (শিগগির বিস্ময়কর প্রশ্ন)। আপনি একটি আপডেট উদাহরণ প্রদান করতে পারেন?
জেস্পার রেন-জেনসেন

4
@ জেস্পার রেন-জেনসেন এই বাক্সটি কোনও কার্যকর উদাহরণের জন্য সম্ভবত খুব ছোট তবে মূলত if (file) close(filename);কোনও নতুন filenameমান নির্ধারণের আগে ।
ট্রিপলি

Aah খুঁজে পাওয়া যায় নি এটা কিভাবে বন্ধ করতে: ; close(filename)। সত্যিই সহজ, তবে এটি সত্যিই উপরের উদাহরণটিকে ঠিক করেছে
জেস্পার রন-জেনসেন

4
@ জেস্পার রেন-জেনসেন আমি আপনার সম্পাদনাটি ফিরিয়ে নিয়েছি কারণ আপনি একটি ভাঙ্গা স্ক্রিপ্ট সরবরাহ করেছেন। অন্যান্য ব্যক্তির উত্তরের উল্লেখযোগ্য সম্পাদনাগুলি সম্ভবত এড়ানো উচিত - আপনার নিজের একটি নতুন উত্তর পোস্ট করার জন্য নির্দ্বিধায় (সম্ভবত একটি সম্প্রদায় উইকি হিসাবে ) যদি আপনি ভাবেন যে একটি পৃথক উত্তর যোগ্যতাযুক্ত।
ট্রিপলি

2

আপনি awk ব্যবহার করতে পারেন। আমি অ্যাজকের সাথে খুব পরিচিত নই, তবে নিম্নলিখিতগুলি আমার পক্ষে কাজ করে বলে মনে হয়েছে। এটি part1.txt, part2.txt, part3.txt এবং part4.txt তৈরি করেছে। মনে রাখবেন, এটি তৈরি করে যে সর্বশেষ partn.txt ফাইলটি খালি। আমি কীভাবে ঠিক করব তা নিশ্চিত নই, তবে আমি নিশ্চিত যে এটি একটি সামান্য টুইটের মাধ্যমে করা সম্ভব। কোন পরামর্শ কেউ?

awk_ Pattern ফাইল:

BEGIN{ fn = "part1.txt"; n = 1 }
{
   print > fn
   if (substr($0,1,2) == "-|") {
       close (fn)
       n++
       fn = "part" n ".txt"
   }
}

bash আদেশ:

awk -f awk_pattern input.file


2

এখানে পাইথন 3 স্ক্রিপ্ট রয়েছে যা ডিলিমিটরদের দ্বারা সরবরাহ করা ফাইলের নামের উপর ভিত্তি করে একাধিক ফাইলগুলিতে একটি ফাইলকে বিভক্ত করে। উদাহরণ ইনপুট ফাইল:

# Ignored

######## FILTER BEGIN foo.conf
This goes in foo.conf.
######## FILTER END

# Ignored

######## FILTER BEGIN bar.conf
This goes in bar.conf.
######## FILTER END

লিপিটি এখানে:

#!/usr/bin/env python3

import os
import argparse

# global settings
start_delimiter = '######## FILTER BEGIN'
end_delimiter = '######## FILTER END'

# parse command line arguments
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--input-file", required=True, help="input filename")
parser.add_argument("-o", "--output-dir", required=True, help="output directory")

args = parser.parse_args()

# read the input file
with open(args.input_file, 'r') as input_file:
    input_data = input_file.read()

# iterate through the input data by line
input_lines = input_data.splitlines()
while input_lines:
    # discard lines until the next start delimiter
    while input_lines and not input_lines[0].startswith(start_delimiter):
        input_lines.pop(0)

    # corner case: no delimiter found and no more lines left
    if not input_lines:
        break

    # extract the output filename from the start delimiter
    output_filename = input_lines.pop(0).replace(start_delimiter, "").strip()
    output_path = os.path.join(args.output_dir, output_filename)

    # open the output file
    print("extracting file: {0}".format(output_path))
    with open(output_path, 'w') as output_file:
        # while we have lines left and they don't match the end delimiter
        while input_lines and not input_lines[0].startswith(end_delimiter):
            output_file.write("{0}\n".format(input_lines.pop(0)))

        # remove end delimiter if present
        if not input_lines:
            input_lines.pop(0)

অবশেষে আপনি কীভাবে এটি চালাচ্ছেন তা এখানে:

$ python3 script.py -i input-file.txt -o ./output-folder/

2

আপনার কাছে csplitথাকলে ব্যবহার করুন ।

যদি আপনি না করেন তবে আপনার কাছে পাইথন রয়েছে ... পার্ল ব্যবহার করবেন না।

ফাইলটি অলসভাবে পড়া

আপনার ফাইলটি একবারে মেমরি ধরে রাখতে খুব বড় হতে পারে - লাইন দ্বারা লাইন পড়া ভাল pre ধরুন ইনপুট ফাইলটির নাম দেওয়া হয়েছে "স্যাম্পলিন":

$ python3 -c "from itertools import count
with open('samplein') as file:
    for i in count():
        firstline = next(file, None)
        if firstline is None:
            break
        with open(f'out{i}', 'w') as out:
            out.write(firstline)
            for line in file:
                out.write(line)
                if line == '-|\n':
                    break"

এটি সম্পূর্ণ ফাইলটিকে মেমোরিতে পড়বে, যার অর্থ এটি অদক্ষ বা এমনকি বড় ফাইলগুলির জন্য ব্যর্থ হবে।
ট্রিপলি

4
@ ট্রিপলি আমি খুব বড় ফাইল হ্যান্ডেল করতে উত্তর আপডেট করেছি।
অ্যারন হল

0
cat file| ( I=0; echo -n "">file0; while read line; do echo $line >> file$I; if [ "$line" == '-|' ]; then I=$[I+1]; echo -n "" > file$I; fi; done )

এবং ফর্ম্যাট সংস্করণ:

#!/bin/bash
cat FILE | (
  I=0;
  echo -n"">file0;
  while read line; 
  do
    echo $line >> file$I;
    if [ "$line" == '-|' ];
    then I=$[I+1];
      echo -n "" > file$I;
    fi;
  done;
)

4
সর্বদা হিসাবে, এটি catঅকেজো
ট্রিপলি

4
@ রিশিন লিঙ্কযুক্ত পৃষ্ঠাটি আরও বিস্তারিতভাবে ব্যাখ্যা করেছে যে কীভাবে আপনি catপ্রতিটি পরিস্থিতিতে একটি ফাইলের মধ্যে এড়াতে পারবেন । আরও আলোচনার সাথে একটি স্ট্যাক ওভারফ্লো প্রশ্ন রয়েছে (যদিও স্বীকৃত উত্তরটি আইএমএইচও বন্ধ রয়েছে); stackoverflow.com/questions/11710552/useless-use-of-cat
tripleee

4
যাইহোক যাইহোক শেলটি এই ধরণের জিনিসটিতে সাধারণত খুব অদক্ষ; যদি আপনি এটি ব্যবহার করতে না পারেন তবে csplitএকটি আওক সমাধান সম্ভবত এই সমাধানটির চেয়ে অনেক বেশি পছন্দনীয় (এমনকি যদি আপনি শেলচেক নেট.এল ইত্যাদির দ্বারা প্রতিবেদনিত সমস্যাগুলি সমাধান করতেই পারেন তবে নোট করুন যে এটি বর্তমানে এর মধ্যে সমস্ত বাগ খুঁজে পায় না)।
ট্রিপলি

@ ট্রিপলি তবে যদি কাজটি অজস্র, সিএসপ্লিট এবং ইত্যাদি ছাড়া করা হয় - তবে কেবল বাশ?
রিশিন

4
তারপরে এটি catএখনও অকেজো, এবং স্ক্রিপ্টের বাকী অংশটি সরল করে একটি ভাল চুক্তি সংশোধন করা যেতে পারে; তবে এটি এখনও ধীর হবে। দেখুন উদাঃ stackoverflow.com/questions/13762625/...
tripleee

0

এই সমস্যাটির জন্য আমি প্রসঙ্গ-বিভাজন লিখেছি: http://stromberg.dnsalias.org/~strombrg/context-split.html

$ ./context-split -h
usage:
./context-split [-s separator] [-n name] [-z length]
        -s specifies what regex should separate output files
        -n specifies how output files are named (default: numeric
        -z specifies how long numbered filenames (if any) should be
        -i include line containing separator in output files
        operations are always performed on stdin

আহ, এটিকে স্ট্যান্ডার্ড csplitইউটিলিটির অনুলিপি হিসাবে মনে হচ্ছে । দেখুন @ রিচার্ডের উত্তর
ট্রিপলি

এটি আসলে সেরা সমাধান ইমো। আমি কোনও কারণে 98 জি মাইএসকিএল ডাম্প এবং সিএসপ্লিট বিভক্ত করতে হয়েছিল আমার সমস্ত র‌্যাম খেয়ে ফেলেছে এবং মারা গেছে। যদিও এটির সময়ে কেবল একটি লাইনের সাথে মিল থাকা দরকার। কোন অর্থ প্রকাশ করে না. এই অজগর স্ক্রিপ্টটি আরও ভাল কাজ করে এবং সমস্ত মেষ খায় না।
স্টিফান মিডজিচ 20'18

0

এখানে একটি পার্ল কোড যা কাজটি করবে

#!/usr/bin/perl
open(FI,"file.txt") or die "Input file not found";
$cur=0;
open(FO,">res.$cur.txt") or die "Cannot open output file $cur";
while(<FI>)
{
    print FO $_;
    if(/^-\|/)
    {
        close(FO);
        $cur++;
        open(FO,">res.$cur.txt") or die "Cannot open output file $cur"
    }
}
close(FO);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.