অত্যন্ত বড় একটি টেক্সট ফাইলের শেষ দুটি লাইন দক্ষতার সাথে সরান


31

আমার কাছে খুব বড় ফাইল রয়েছে (GB 400 গিগাবাইট) এবং এখান থেকে আমার শেষ দুটি লাইন সরিয়ে ফেলতে হবে। আমি ব্যবহার করার চেষ্টা করেছি sed, তবে আমি হাল ছাড়ার আগে কয়েক ঘন্টা ধরে এটি চলেছিল। এটি করার কোনও দ্রুত উপায় আছে, বা আমি আটকে আছি sed?


6
আপনি GNU মাথা চেষ্টা করে দেখতে পারেন। head -n -2 file
ব্যবহারকারী31894

সেখানে দেওয়া এক লাইন পার্ল এবং জাভা প্রস্তাবনার একটি দম্পতি ছিল stackoverflow.com/questions/2580335/...
mtrw

উত্তর:


31

এটি কত দ্রুত হয় তা দেখার জন্য আমি কোনও বড় ফাইলে এটি চেষ্টা করি নি, তবে এটি মোটামুটি দ্রুত হওয়া উচিত।

কোনও ফাইলের শেষে থেকে লাইনগুলি সরাতে স্ক্রিপ্টটি ব্যবহার করতে:

./shorten.py 2 large_file.txt

এটি ফাইলের শেষের দিকে অনুসন্ধান করে, শেষ অক্ষরটি একটি নতুন লাইন কিনা তা যাচাই করে তা পরীক্ষা করে, তারপরে প্রতিটি চরিত্রকে একবারে পিছনে যেতে পারা যায় যতক্ষণ না এটি তিনটি নতুন লাইন খুঁজে পাওয়া যায় এবং ঠিক সেই বিন্দুটির পরে ফাইলটি কেটে যায়। পরিবর্তন জায়গায় করা হয়।

সম্পাদনা: আমি নীচে একটি পাইথন ২.৪ সংস্করণ যুক্ত করেছি।

পাইথন 2.5 / 2.6 এর জন্য এখানে একটি সংস্করণ রয়েছে:

#!/usr/bin/env python2.5
from __future__ import with_statement
# also tested with Python 2.6

import os, sys

if len(sys.argv) != 3:
    print sys.argv[0] + ": Invalid number of arguments."
    print "Usage: " + sys.argv[0] + " linecount filename"
    print "to remove linecount lines from the end of the file"
    exit(2)

number = int(sys.argv[1])
file = sys.argv[2]
count = 0

with open(file,'r+b') as f:
    f.seek(0, os.SEEK_END)
    end = f.tell()
    while f.tell() > 0:
        f.seek(-1, os.SEEK_CUR)
        char = f.read(1)
        if char != '\n' and f.tell() == end:
            print "No change: file does not end with a newline"
            exit(1)
        if char == '\n':
            count += 1
        if count == number + 1:
            f.truncate()
            print "Removed " + str(number) + " lines from end of file"
            exit(0)
        f.seek(-1, os.SEEK_CUR)

if count < number + 1:
    print "No change: requested removal would leave empty file"
    exit(3)

এখানে পাইথন 3 সংস্করণ রয়েছে:

#!/usr/bin/env python3.0

import os, sys

if len(sys.argv) != 3:
    print(sys.argv[0] + ": Invalid number of arguments.")
    print ("Usage: " + sys.argv[0] + " linecount filename")
    print ("to remove linecount lines from the end of the file")
    exit(2)

number = int(sys.argv[1])
file = sys.argv[2]
count = 0

with open(file,'r+b', buffering=0) as f:
    f.seek(0, os.SEEK_END)
    end = f.tell()
    while f.tell() > 0:
        f.seek(-1, os.SEEK_CUR)
        print(f.tell())
        char = f.read(1)
        if char != b'\n' and f.tell() == end:
            print ("No change: file does not end with a newline")
            exit(1)
        if char == b'\n':
            count += 1
        if count == number + 1:
            f.truncate()
            print ("Removed " + str(number) + " lines from end of file")
            exit(0)
        f.seek(-1, os.SEEK_CUR)

if count < number + 1:
    print("No change: requested removal would leave empty file")
    exit(3)

এখানে পাইথন ২.৪ সংস্করণ রয়েছে:

#!/usr/bin/env python2.4

import sys

if len(sys.argv) != 3:
    print sys.argv[0] + ": Invalid number of arguments."
    print "Usage: " + sys.argv[0] + " linecount filename"
    print "to remove linecount lines from the end of the file"
    sys.exit(2)

number = int(sys.argv[1])
file = sys.argv[2]
count = 0
SEEK_CUR = 1
SEEK_END = 2

f = open(file,'r+b')
f.seek(0, SEEK_END)
end = f.tell()

while f.tell() > 0:
    f.seek(-1, SEEK_CUR)
    char = f.read(1)
    if char != '\n' and f.tell() == end:
        print "No change: file does not end with a newline"
        f.close()
        sys.exit(1)
    if char == '\n':
        count += 1
    if count == number + 1:
        f.truncate()
        print "Removed " + str(number) + " lines from end of file"
        f.close()
        sys.exit(0)
    f.seek(-1, SEEK_CUR)

if count < number + 1:
    print "No change: requested removal would leave empty file"
    f.close()
    sys.exit(3)

আমাদের সিস্টেমটি অজগর ২.৪ চলছে, এবং আমি নিশ্চিত না যে আমাদের কোনও পরিষেবা এতে নির্ভর করে কিনা, এটি কি এতে কাজ করবে?
রাশ ব্র্যাডবেরি

@ রুস: আমি পাইথন ২.৪ এর জন্য একটি সংস্করণ যুক্ত করেছি।
পরবর্তী বিজ্ঞপ্তি না দেওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।

1
একেবারে আশ্চর্যজনক! মোহন মত কাজ করেছে এবং এক সেকেন্ডেরও কম সময়!
রাশ ব্র্যাডবেরি

12

আপনি GNU মাথা চেষ্টা করতে পারেন

head -n -2 file

এটি সহজ হওয়ায় এটি সেরা সমাধান।
xiao

1
এটি তাকে ফাইলের শেষ দুটি লাইন দেখাবে, তবে সেগুলি তার ফাইল থেকে সরিয়ে দেবে না..আর আমার সিস্টেমেও কাজ করে নাhead: illegal line count -- -2
SooDesuNe

2
@ সুডেসুএন: না এটি ম্যানুয়াল অনুসারে শুরু থেকে শেষ পর্যন্ত দুটি লাইন পর্যন্ত সমস্ত লাইন মুদ্রণ করবে। যাইহোক, এটি একটি ফাইলে পুনঃনির্দেশ করা প্রয়োজন, এবং তারপরে এই ফাইলটি জায়ান্ট হওয়ার সাথে সমস্যা রয়েছে, সুতরাং এটি এই সমস্যার সঠিক সমাধান নয়।
ড্যানিয়েল অ্যান্ডারসন 21

+1 কেন এটি সঠিক উত্তর হিসাবে গ্রহণ করা হচ্ছে না? এটি দ্রুত, সহজ এবং প্রত্যাশার মতো কাজ করে।
এএফএক্সএক্স

6
@ পেটারমারেক এবং অন্যান্য: সমস্যাটি হ'ল এটি একটি বিশাল ফাইল সম্পর্কিত। এই সমাধানটির জন্য পুরো ফাইলটি একটি পাইপের মাধ্যমে খাওয়ানো এবং সমস্ত ডেটা নতুন স্থানে পুনর্লিখনের প্রয়োজন হবে - এবং প্রশ্নের পুরো বিষয়টি হ'ল এড়ানো। একটি অন্তর্নিহিত সমাধানের প্রয়োজন যেমন গ্রহণযোগ্য উত্তরের একটি।
ড্যানিয়েল অ্যান্ডারসন

7

আমি দেখতে পাচ্ছি আমার ডেবিয়ান স্কুইজ / টেস্টিং সিস্টেমগুলি (তবে লেনি / স্থিতিশীল নয়) "কোরুটিলস" প্যাকেজের অংশ হিসাবে একটি "কাটা" কমান্ড অন্তর্ভুক্ত রয়েছে।

এটি দিয়ে আপনি সাধারণভাবে কিছু করতে পারেন

truncate --size=-160 myfile

ফাইলটির শেষে থেকে 160 বাইট অপসারণ করতে (স্পষ্টত আপনার কতগুলি অক্ষর অপসারণ করতে হবে তা সঠিকভাবে নির্ধারণ করতে হবে)।


এটি স্থানের পরিবর্তে ফাইলটি পরিবর্তিত করার কারণে এটি দ্রুততম রুট হবে এবং সুতরাং ফাইলের অনুলিপি বা পার্স করার প্রয়োজন নেই। তবে, আপনাকে এখনও কতগুলি বাইট অপসারণ করতে হবে তা পরীক্ষা করে দেখতে হবে ... আমি / অনুমান / একটি সাধারণ ddস্ক্রিপ্ট এটি করবে (ফে লাস্ট কিলোবাইট পেতে তার জন্য ইনপুট অফসেট নির্দিষ্ট করতে হবে এবং তারপরে ব্যবহার করতে হবে tail -2 | LANG= wc -c, বা এর মতো স্ট্যাথ))
লিওরি

আমি CentOS ব্যবহার করছি, তাই না আমার ছাঁটাই নেই। যাইহোক, আমি ঠিক এটিই খুঁজছি।
রাশ ব্র্যাডবেরি

tailবড় ফাইলগুলির পক্ষেও কার্যকর, - tail | wc -cছাঁটাই করার জন্য বাইটের সংখ্যা গণনা করতে ব্যবহার করতে পারেন ।
krlMLr

6

সেডের সমস্যাটি হ'ল এটি একটি স্ট্রিম এডিটর - এটি যদি আপনি কেবলমাত্র শেষের দিকে পরিবর্তন করতে চান তবে এটি পুরো ফাইলটি প্রক্রিয়া করবে। সুতরাং যাই হোক না কেন, আপনি লাইন লাইন একটি নতুন 400GB ফাইল তৈরি করছেন। যে কোনও সম্পাদক যা পুরো ফাইলটিতে পরিচালনা করে তাদের সম্ভবত এই সমস্যাটি হবে।

আপনি যদি লাইনের সংখ্যা জানেন তবে আপনি ব্যবহার করতে পারেন headতবে এটি আবার বিদ্যমান ফাইলটি পরিবর্তে পরিবর্তে একটি নতুন ফাইল তৈরি করে। আমার ধারণা, আপনি ক্রিয়াটির সরলতা থেকে গতি অর্জন করতে পারেন।

আপনি পারে ব্যবহার করে আরো ভালভাবে ভাগ্য আছে splitসম্পাদনা গত এক, এবং তারপর ব্যবহার করে, ছোট টুকরা মধ্যে ফাইল বিরতি catআবার একত্রিত করতে, কিন্তু আমি নিশ্চিত যদি এটা কোন ভাল হবে না। আমি লাইনগুলির চেয়ে বাইট গণনাগুলি ব্যবহার করব, অন্যথায় এটি সম্ভবত দ্রুততর হবে না - আপনি এখনও একটি নতুন 400 জিবি ফাইল তৈরি করতে যাচ্ছেন।


2

ভিআইএম চেষ্টা করুন ... আমি নিশ্চিত নই যে এটি কৌশলটি করবে কিনা, কারণ আমি এটি এত বড় ফাইলটিতে কখনও ব্যবহার করি নি, তবে অতীতে ছোট বড় ফাইলগুলিতে এটি ব্যবহার করেছি।


আমি বিশ্বাস করি যে ভিম সম্পাদনা করার সময় কেবলমাত্র বাফারের আশেপাশে যা লোড করা হয়, তা কীভাবে সংরক্ষণ হয় সে সম্পর্কে আমার কোনও ধারণা নেই।
ফোশি

ফাইলটি লোড করার চেষ্টা করার সময়
ভিএম

আচ্ছা যদি এটি ঝুলে থাকে তবে আহ এটির জন্য অপেক্ষা করুন। এটি লোড করা শুরু করুন, কাজে যান, ঘরে আসুন, দেখুন এটি হয়েছে কিনা।
leeand00

2

1

কোন ধরণের ফাইল এবং কোন ফর্ম্যাটে? পার্ল নির্ভর কোন ধরণের ফাইলের উপর নির্ভরশীল - টেক্সট, গ্রাফিক্স, বাইনারি? এটি কীভাবে ফর্ম্যাট করা হয় - সিএসভি, টিএসভি ...


এটি পাইপ ডিলিমেটেড টেক্সট ফর্ম্যাট করা আছে, তবে শেষ 2 টি লাইন একক কলাম যা প্রতিটি আমার আমদানি ভঙ্গ করবে তাই আমার তাদের অপসারণ প্রয়োজন
রাশ ব্র্যাডবেরি

এই ক্ষেত্রে একটি বিকল্প বিকল্প মোকাবেলা করতে "আমদানি" যা কিছু করে তা স্থির করে দিচ্ছে?
টিমডে

কোনও আমদানি ইনফোবাইটের "লোড ডেটা
ইনফাইলে

1

আপনি যদি বাইটটিতে ফাইলের আকার জানেন (400000000160 বলুন) এবং আপনি জানেন যে শেষ দুটি লাইনের ফালা ফেলার জন্য আপনাকে ঠিক 160 টি অক্ষর অপসারণ করতে হবে, তবে এর মতো কিছু

dd if=originalfile of=truncatedfile ibs=1 count=400000000000

কৌতুক করা উচিত। আমি যুগে যুগে ক্রুদ্ধ হয়ে ডিডি ব্যবহার করেছি; আমার মনে হচ্ছে আপনি যদি আরও বড় আকারের ব্লক আকার ব্যবহার করেন তবে জিনিসগুলি দ্রুত গতিতে চলেছে তবে আপনি এটি করতে পারেন কিনা তা নির্ভর করে আপনি যে লাইনগুলি ফেলে দিতে চান তা কোনও একাধিকতে রয়েছে কিনা depends

একটি নির্দিষ্ট আকারে পাঠ্য রেকর্ডগুলি প্যাড করার জন্য ডিডির আরও কিছু বিকল্প রয়েছে যা প্রাথমিক পাস হিসাবে কার্যকর হতে পারে।


আমি এটি চেষ্টা করেছিলাম, তবে এটি সেডের মতোই গতিতে চলছিল। এটি 10 ​​মিনিটে প্রায় 200MB লিখেছিল, এই হারে এটি আক্ষরিকভাবে কয়েক ঘন্টা সময় নিতে শুরু করবে।
রাশ ব্র্যাডবেরি

1

যদি "ট্রাঙ্কেট" কমান্ডটি আপনার সিস্টেমে উপলব্ধ না হয় (আমার অন্য উত্তরটি দেখুন), একটি নির্দিষ্ট দৈর্ঘ্যে কোনও ফাইলকে কাটাতে সিস্টেম কল করার জন্য "ম্যান 2 ট্রুঙ্কেট" দেখুন।

স্পষ্টতই আপনাকে জানতে হবে যে আপনাকে ফাইলটি কেটে ফেলতে হবে (অক্ষরের দৈর্ঘ্যের দুটি লাইনের দৈর্ঘ্য; কোনও সিআর / এলএফ অক্ষর গণনা করতে ভুলবেন না) you

এটি চেষ্টা করার আগে ফাইলটির একটি ব্যাকআপ তৈরি করুন!


1

আপনি যদি ইউনিক্স-স্টাইলের সমাধানগুলি পছন্দ করেন তবে আপনার কাছে তিনটি লাইন কোড (ম্যাক এবং লিনাক্সে পরীক্ষিত) ব্যবহার করে সংরক্ষণ এবং ইন্টারেক্টিভ লাইন কাটা থাকতে পারে।

ছোট + নিরাপদ ইউনিক্স-স্টাইলের লাইন কাটা (নিশ্চিতকরণের জন্য জিজ্ঞাসা করে):

n=2; file=test.csv; tail -n $n $file &&
read -p "truncate? (y/N)" -n1 key && [ "$key" == "y" ] &&
perl -e "truncate('$file', `wc -c <$file` - `tail -n $n $file | wc -c` )"

এই সমাধানটি কয়েকটি সাধারণ ইউনিক্স-সরঞ্জামগুলির উপর নির্ভর করে, তবে এখনও এর perl -e "truncate(file,length)"নিকটতম প্রতিস্থাপন হিসাবে ব্যবহার করে truncate(1), যা সমস্ত সিস্টেমে উপলব্ধ নয়।

আপনি নিম্নলিখিত বিস্তৃত পুনরায় ব্যবহারযোগ্য শেল প্রোগ্রামটিও ব্যবহার করতে পারেন, যা একটি ব্যবহারের তথ্য সরবরাহ করে এবং কাটছাঁটি নিশ্চিতকরণ, বিকল্প বিশ্লেষণ এবং ত্রুটি পরিচালনার বৈশিষ্ট্যগুলি সরবরাহ করে।

বিস্তৃত লাইন কাটা স্ক্রিপ্ট :

#!/usr/bin/env bash

usage(){
cat <<-EOF
  Usage:   $0 [-n NUM] [-h] FILE
  Options:
  -n NUM      number of lines to remove (default:1) from end of FILE
  -h          show this help
EOF
exit 1
}

num=1

for opt in $*; do case $opt in
  -n) num=$2;                 shift;;
  -h) usage;                  break;;
  *)  [ -f "$1" ] && file=$1; shift;;
esac done

[ -f "$file" ] || usage

bytes=`wc -c <$file`
size=`tail -n $num $file | wc -c`

echo "using perl 'truncate' to remove last $size of $bytes bytes:"
tail -n $num $file
read -p "truncate these lines? (y/N)" -n1 key && [ "$key" == "y" ] &&
perl -e "truncate('$file', $bytes - $size )"; echo ""
echo "new tail is:"; tail $file

এখানে ব্যবহারের উদাহরণ দেওয়া হল:

$ cat data/test.csv
1 nice data
2 cool data
3 just data

GARBAGE to be removed (incl. empty lines above and below)

$ ./rmtail.sh -n 3 data/test.csv
using perl 'truncate' to remove last 60 of 96 bytes:

GARBAGE to be removed (incl. empty lines above and below)

truncate these lines? (y/N)y
new tail is:
1 nice data
2 cool data
3 just data
$ cat data/test.csv
1 nice data
2 cool data
3 just data

0
#! / বিন / SH

সম্পাদনা "$ 1" << এখানে
$
ঘ
ঘ
W
এখানে

পরিবর্তে জায়গায় করা হয়। এটি পাইথন স্ক্রিপ্টের চেয়ে সহজ এবং দক্ষ।


আমার সিস্টেমে দশ মিলিয়ন লাইন এবং 57MB এর বেশি সমন্বিত একটি পাঠ্য ফাইল ব্যবহার করে edআমার পাইথন স্ক্রিপ্টের চেয়ে 100 গুণ বেশি সময় লেগেছিল। আমি কেবলমাত্র কল্পনা করতে পারি যে OP০০০ গুণ বড় ওপি-র ফাইলের জন্য আরও কত পার্থক্য হবে।
পরবর্তী বিজ্ঞপ্তি না দেওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।

0

অনুরূপ সমস্যা সমাধানের জন্য গৃহীত উত্তরটি পরিবর্তন করে। এন লাইনগুলি সরাতে সামান্য একটু টুইট করা যেতে পারে।

import os

def clean_up_last_line(file_path):
    """
    cleanup last incomplete line from a file
    helps with an unclean shutdown of a program that appends to a file
    if \n is not the last character, remove the line
    """
    with open(file_path, 'r+b') as f:
        f.seek(0, os.SEEK_END)

        while f.tell() > 0: ## current position is greater than zero
            f.seek(-1, os.SEEK_CUR)

            if f.read(1) == '\n':
                f.truncate()
                break

            f.seek(-1, os.SEEK_CUR) ## don't quite understand why this has to be called again, but it doesn't work without it

এবং সম্পর্কিত পরীক্ষা:

import unittest

class CommonUtilsTest(unittest.TestCase):

    def test_clean_up_last_line(self):
        """
        remove the last incomplete line from a huge file
        a line is incomplete if it does not end with a line feed
        """
        file_path = '/tmp/test_remove_last_line.txt'

        def compare_output(file_path, file_data, expected_output):
            """
            run the same test on each input output pair
            """
            with open(file_path, 'w') as f:
                f.write(file_data)

            utils.clean_up_last_line(file_path)

            with open(file_path, 'r') as f:
                file_data = f.read()
                self.assertTrue(file_data == expected_output, file_data)        

        ## test a multiline file
        file_data = """1362358424445914,2013-03-03 16:53:44,34.5,151.16345879,b
1362358458954466,2013-03-03 16:54:18,34.5,3.0,b
1362358630923094,2013-03-03 16:57:10,34.5,50.0,b
136235"""

        expected_output = """1362358424445914,2013-03-03 16:53:44,34.5,151.16345879,b
1362358458954466,2013-03-03 16:54:18,34.5,3.0,b
1362358630923094,2013-03-03 16:57:10,34.5,50.0,b
"""        
        compare_output(file_path, file_data, expected_output)

        ## test a file with no line break
        file_data = u"""1362358424445914,2013-03-03 16:53:44,34.5,151.16345879,b"""
        expected_output = "1362358424445914,2013-03-03 16:53:44,34.5,151.16345879,b"
        compare_output(file_path, file_data, expected_output)

        ## test a file a leading line break
        file_data = u"""\n1362358424445914,2013-03-03 16:53:44,34.5,151.16345879,b"""
        expected_output = "\n"
        compare_output(file_path, file_data, expected_output)

        ## test a file with one line break
        file_data = u"""1362358424445914,2013-03-03 16:53:44,34.5,151.16345879,b\n""" 
        expected_output = """1362358424445914,2013-03-03 16:53:44,34.5,151.16345879,b\n""" 
        compare_output(file_path, file_data, expected_output)

        os.remove(file_path)


if __name__ == '__main__':
    unittest.main()

0

আপনি প্রাক্তন মোডে ভিম ব্যবহার করতে পারেন:

ex -sc '-,d|x' file
  1. -, শেষ 2 লাইন নির্বাচন করুন

  2. d মুছে ফেলা

  3. x সংরক্ষণ করেন এবং বন্ধ করেন

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