ইউনিক্স - একটি বিশাল .gz ফাইলটি লাইন দ্বারা বিভক্ত করুন


16

আমি নিশ্চিত যে কারও নীচের প্রয়োজনটি আছে, একটি বিশাল .gz ফাইলকে লাইন দিয়ে বিভক্ত করার দ্রুত উপায় কী? অন্তর্নিহিত পাঠ্য ফাইলটিতে 120 মিলিয়ন সারি রয়েছে। আমার কাছে পুরো ফাইলটি একবারে গিনজিপ করার মতো পর্যাপ্ত ডিস্কের জায়গা নেই তাই আমি ভাবছিলাম যে কেউ যদি বাশ / পার্ল স্ক্রিপ্ট বা সরঞ্জাম সম্পর্কে জানেন যা ফাইলটি (.gz বা অভ্যন্তরীণ .txt) কে 3x 40mn লাইন ফাইলগুলিতে বিভক্ত করতে পারে? । অর্থাত্ এটিকে কল করা:

    bash splitter.sh hugefile.txt.gz 4000000 1
 would get lines 1 to 40 mn    
    bash splitter.sh hugefile.txt.gz 4000000 2
would get lines 40mn to 80 mn
    bash splitter.sh hugefile.txt.gz 4000000 3
would get lines 80mn to 120 mn

সম্ভবত এইগুলি সমাধানের একটি সিরিজ করছে বা বন্দুকদ্বার-সি পুরো ফাইল আনজিপড করার জন্য পর্যাপ্ত স্থানের প্রয়োজন হবে (যেমন মূল সমস্যা): বন্দুকদ-সি विशालফাইল.txt.gz | মাথা 4000000

দ্রষ্টব্য: আমি অতিরিক্ত ডিস্ক পেতে পারি না

ধন্যবাদ!


1
আপনি কি চান যে ফলস্বরূপ ফাইলগুলি আবার gziped করা উচিত?

আপনি আইপিতে গানজিপ ব্যবহার করতে পারেন। বাকিগুলি মাথা এবং লেজ দিয়ে করা যায়
ইনগো

@ টিচোড্রোমা - ​​না তাদের আর জিজিপ করার দরকার নেই। তবে আমি সমস্ত বিভক্ত পাঠ্য ফাইল একসাথে সংরক্ষণ করতে পারিনি। সুতরাং আমি প্রথম বিভক্তি পেতে চাই, এটি দিয়ে স্টাফ করুন, তারপরে প্রথম বিভাজন মুছুন এবং তারপরে ২ য় স্প্লিট.টেকটি শেষ পর্যন্ত আসল জিজেড সরিয়ে
ফেলুন

1
@ টুপ: স্পষ্টতার জন্য ধন্যবাদ। মনে রাখবেন যে আপনি আপনার মন্তব্যটি কোনও মন্তব্যে না রেখে বরং স্পষ্ট করে বলতে চাইলে সাধারণত আপনার সম্পাদনা করা ভাল; যেভাবে সবাই এটি দেখতে পাবেন।
sleske

গ্রহণযোগ্য উত্তরটি ভাল যদি আপনি কেবল খণ্ডগুলির একটি ভগ্নাংশ চান, এবং সেগুলি আগেই জানেন না। আপনি যদি একবারে সমস্ত খণ্ড জেনারেট করতে চান তবে বিভক্তির ভিত্তিতে সমাধানগুলি O (N²) এর পরিবর্তে O (N) এর চেয়ে অনেক দ্রুত হবে।
b0fh

উত্তর:


11

কীভাবে এটি করা যায় তা নির্ভর করে আপনি কী চান:

  • আপনি কি বড় ফাইলের একটি অংশই বের করতে চান?
  • অথবা আপনি কি একযোগে সমস্ত অংশ তৈরি করতে চান?

আপনি যদি একটি চান ফাইলের একক অংশ , আপনার ধারণা ব্যবহার করতে gunzipএবং headঅধিকার। তুমি ব্যবহার করতে পার:

gunzip -c hugefile.txt.gz | head -n 4000000

এটি স্ট্যান্ডার্ড আউটে প্রথম 4000000 লাইন আউটপুট দেয় - আপনি সম্ভবত ডেটা সহ কিছু করার জন্য সম্ভবত অন্য পাইপ যুক্ত করতে চান।

অন্যান্য অংশগুলি পেতে, আপনি headএবং এর tailমতো সংমিশ্রণটি ব্যবহার করবেন :

gunzip -c hugefile.txt.gz | head -n 8000000 |tail -n 4000000

দ্বিতীয় ব্লক পেতে।

সম্ভবত এই সমাধানগুলির একটি সিরিজ করছে বা বন্দুক-সি-কে পুরো ফাইল আনজিপড করার জন্য পর্যাপ্ত স্থানের প্রয়োজন হবে?

না, এর gunzip -cজন্য কোনও ডিস্ক জায়গার প্রয়োজন হয় না - এটি মেমরির সমস্ত কিছু করে, তারপরে স্টাডআউটকে প্রবাহিত করে।


আপনি যদি একযোগে সমস্ত অংশ তৈরি করতে চান তবে একক কমান্ডের সাহায্যে সেগুলি তৈরি করা আরও দক্ষ, কারণ ইনপুট ফাইলটি কেবল একবারই পঠিত হয়। একটি ভাল সমাধান ব্যবহার করা হয় split; বিস্তারিত জানার জন্য জিম এমকনামার উত্তর দেখুন।


1
পারফরম্যান্স দর্শন থেকে: gzip আসলে পুরো ফাইল আনজিপ করে? অথবা এটি কি "জাদুকরীভাবে" জানতে সক্ষম যে কেবল 4 মিলিয়ন লাইনের প্রয়োজন?
অ্যালোস মাহডাল

3
@ অলিসমহদল: আসলে, এটি একটি ভাল পৃথক প্রশ্ন হবে :-)। সংক্ষিপ্ত সংস্করণ: gzipসীমাটি (যা একটি ভিন্ন প্রক্রিয়া থেকে আসে) সম্পর্কে জানে না। যদি headএটি ব্যবহার করা হয়, headএটি যথেষ্ট পরিমাণে প্রাপ্ত হলে প্রস্থান করবে এবং এটি প্রচার করবে gzip(SIGPIPE এর মাধ্যমে, উইকিপিডিয়া দেখুন)। জন্য tailযদি সম্ভব না হয়, তাই হ্যাঁ, gzipসবকিছু ডিকম্প্রেস হবে।
স্লেসকে

তবে আপনি যদি আগ্রহী হন তবে আপনার অবশ্যই এটি আলাদা প্রশ্ন হিসাবে জিজ্ঞাসা করা উচিত।
স্লেস

20

পাইপ বিভক্ত করতে ফাইলটি খুলতে গানজিপ-সি বা জ্যাক্যাট ব্যবহার করুন

gunzip -c bigfile.gz | split -l 400000

বিভাজন কমান্ডে আউটপুট স্পেসিফিকেশন যুক্ত করুন।


3
এটি গ্রহণযোগ্য উত্তরের চেয়ে ব্যাপকভাবে কার্যকর, যদি না আপনি কেবল বিভক্ত অংশগুলির একটি ভগ্নাংশ প্রয়োজন। দয়া করে upvote।
b0fh

1
@ বি0ফাহ: হ্যাঁ, আপনি ঠিক বলেছেন। উত্সাহিত, এবং আমার জবাব রেফারেন্স :-)।
sleske

অবশ্যই সেরা উত্তর।
স্টিফেন ব্লুম

আউটপুট স্পেসগুলি কী কী যাতে আউটপুটগুলি .gz ফাইলগুলি নিজের হয়?
কোয়েটজলকোটল

7

আপনি যখন (পুনর্বারযোগ্য নয়) প্রবাহে কাজ করছেন, আপনি N + থেকে শুরু করে লাইন পেতে লেজের '+ N' ফর্মটি ব্যবহার করতে চাইবেন।

zcat hugefile.txt.gz | head -n 40000000
zcat hugefile.txt.gz | tail -n +40000001 | head -n 40000000
zcat hugefile.txt.gz | tail -n +80000001 | head -n 40000000


3

.Gz ফাইলগুলিকে সরাসরি .gz ফাইলগুলিতে বিভক্ত করুন:

zcat bigfile.gz | split -l 400000 --filter='gzip > $FILE.gz'

আমার মনে হয় ওপি এটিই চেয়েছিল, কারণ তার খুব বেশি জায়গা নেই।


2

ডিরেক্টরি থেকে ফাইলগুলির গ্লোববেড সেট খোলার জন্য এখানে অজগর স্ক্রিপ্ট রয়েছে, প্রয়োজনে সেগুলি বন্দুক করুন এবং লাইন লাইন সেগুলি পড়ুন। এটি কেবল ফাইলের নামগুলি এবং বর্তমান লাইন, এবং কিছুটা ওভারহেড ধরে রাখার জন্য মেমরির প্রয়োজনীয় স্থানটি ব্যবহার করে।

#!/usr/bin/env python
import gzip, bz2
import os
import fnmatch

def gen_find(filepat,top):
    for path, dirlist, filelist in os.walk(top):
        for name in fnmatch.filter(filelist,filepat):
            yield os.path.join(path,name)

def gen_open(filenames):
    for name in filenames:
        if name.endswith(".gz"):
            yield gzip.open(name)
        elif name.endswith(".bz2"):
            yield bz2.BZ2File(name)
        else:
            yield open(name)

def gen_cat(sources):
    for s in sources:
        for item in s:
            yield item

def main(regex, searchDir):
    fileNames = gen_find(regex,searchDir)
    fileHandles = gen_open(fileNames)
    fileLines = gen_cat(fileHandles)
    for line in fileLines:
        print line

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Search globbed files line by line', version='%(prog)s 1.0')
    parser.add_argument('regex', type=str, default='*', help='Regular expression')
    parser.add_argument('searchDir', , type=str, default='.', help='list of input files')
    args = parser.parse_args()
    main(args.regex, args.searchDir)

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


2

এখানে একটি পার্ল প্রোগ্রাম রয়েছে যা স্টিডিন পড়তে এবং লাইনগুলি বিভক্ত করতে প্রতিটি ক্লাম্পকে পৃথক কমান্ডে পাইপ করে যা একে আলাদা গন্তব্যে নিয়ে যাওয়ার জন্য শেল ভেরিয়েবল $ এসপিএলআইটি ব্যবহার করতে পারে। আপনার ক্ষেত্রে এটির সাথে অনুরোধ করা হবে

zcat hugefile.txt.gz | perl xsplit.pl 40000000 'cat > tmp$SPLIT.txt; do_something tmp$SPLIT.txt; rm tmp$SPLIT.txt'

দুঃখিত, কমান্ড-লাইন প্রক্রিয়াজাতকরণটি কিছুটা ক্লডগি তবে আপনি ধারণাটি পেয়েছেন।

#!/usr/bin/perl -w
#####
# xsplit.pl: like xargs but instead of clumping input into each command's args, clumps it into each command's input.
# Usage: perl xsplit.pl LINES 'COMMAND'
# where: 'COMMAND' can include shell variable expansions and can use $SPLIT, e.g.
#   'cat > tmp$SPLIT.txt'
# or:
#   'gzip > tmp$SPLIT.gz'
#####
use strict;

sub pipeHandler {
    my $sig = shift @_;
    print " Caught SIGPIPE: $sig\n";
    exit(1);
}
$SIG{PIPE} = \&pipeHandler;

my $LINES = shift;
die "LINES must be a positive number\n" if ($LINES <= 0);
my $COMMAND = shift || die "second argument should be COMMAND\n";

my $line_number = 0;

while (<STDIN>) {
    if ($line_number%$LINES == 0) {
        close OUTFILE;
        my $split = $ENV{SPLIT} = sprintf("%05d", $line_number/$LINES+1);
        print "$split\n";
        my $command = $COMMAND;
        open (OUTFILE, "| $command") or die "failed to write to command '$command'\n";
    }
    print OUTFILE $_;
    $line_number++;
}

exit 0;
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.