bash

2010-05-08 13 views
14

के साथ एक विशाल फ़ाइल में एक पंक्ति प्राप्त करना मैं 3 गीग टेक्स्ट फ़ाइल में एक विशेष पंक्ति कैसे प्राप्त कर सकता हूं। सभी लाइनें है:bash

  • एक ही लंबाई, और
  • \n द्वारा सीमांकित कर रहे हैं।

और मुझे मांग पर कोई लाइन प्राप्त करने में सक्षम होना चाहिए।

यह कैसे किया जा सकता है? केवल एक लाइन लौटा दी जानी चाहिए।

उत्तर

18

यदि सब लाइनों एक ही लंबाई से, सबसे अच्छा तरीका अब तक dd(1) उपयोग करें और यह एक छोड़ पैरामीटर देने के लिए किया जाएगा।

ब्लॉक आकार (न्यू लाइन सहित) प्रत्येक लाइन की लंबाई हो, तो आप कर सकते हैं:

$ dd if=filename bs=<line-length> skip=<line_no - 1> count=1 2>/dev/null 

विचार सभी पिछले लाइनों (skip=<line_no - 1>) अतीत की तलाश और एक पंक्ति को पढ़ने के लिए है (count=1)। चूंकि ब्लॉक आकार लाइन लंबाई (bs=<line-length>) पर सेट है, प्रत्येक ब्लॉक प्रभावी रूप से एक पंक्ति है। Stderr को पुनर्निर्देशित करें ताकि आपको अंत में परेशान आंकड़े न मिलें।

यह एक प्रोग्राम के माध्यम से सभी लाइनों को पढ़ने के लिए लाइनों को स्ट्रीम करने से पहले और अधिक फेंकने से पहले और अधिक कुशल होना चाहिए, क्योंकि dd आपको उस स्थिति की तलाश करेगा जो आप फ़ाइल में चाहते हैं और केवल एक पंक्ति पढ़ना चाहते हैं फ़ाइल से डेटा का।

+0

+1। मूल रूप से अतिरिक्त बाद के रिकॉर्ड-आकार स्निपेट के बाद मेरे बाद के समाधान के समान ही प्रश्न में जोड़ा गया था, लेकिन इसका अपना अलग-अलग लाभ है कि आप अपना खुद का प्रोग्राम लिखने की आवश्यकता न लें। – paxdiablo

+1

यह इतना बेवकूफ है। हे। डीडी, मुझे यह पसंद है। – JavaRocky

3

बस का उपयोग करने के यदि यह एक निश्चित रिकार्ड लंबाई फ़ाइल नहीं है और आप लाइन पर अनुक्रमण के कुछ प्रकार नहीं करते शुरू होता है, आपका सर्वश्रेष्ठ दांव है:

head -n N filespec | tail -1 

जहां N लाइन नंबर है तुम्हें चाहिए।

यह एक 3 जीबी फ़ाइल दुर्भाग्य के लिए कोड का सबसे अच्छा प्रदर्शन टुकड़ा होने के लिए नहीं जा रहा है लेकिन वहाँ इसे बेहतर बनाने के तरीके हैं।

यदि फ़ाइल बहुत बार नहीं बदलती है, तो आप इसे अनुक्रमणित करने पर विचार करना चाहेंगे। इसके द्वारा मेरा मतलब है कि अन्य फ़ाइल में लाइन ऑफसेट्स के साथ निश्चित लंबाई रिकॉर्ड के रूप में फ़ाइल है।

तो फ़ाइल:

0000000000 
0000000017 
0000000092 
0000001023 

आप प्रत्येक पंक्ति का पता लगाने के लिए एक तेजी से रास्ता देना होगा। बस वांछित लाइन नंबर को इंडेक्स रिकॉर्ड आकार से गुणा करें और इंडेक्स फ़ाइल में वहां खोजें।

तब मुख्य फ़ाइल में तलाश करने के लिए ताकि आप अगले न्यू लाइन चरित्र जब तक पढ़ सकते हैं उस स्थान पर मूल्य का उपयोग करें।

तो लाइन 3 के लिए, आप अनुक्रमणिका फ़ाइल में 33 करने की कोशिश करेगी (सूचकांक रिकॉर्ड लंबाई 10 वर्णों से अधिक न्यू लाइन के लिए एक और है)। वहां मूल्य को पढ़ना, 0000000092, आपको मुख्य फ़ाइल में उपयोग करने के लिए ऑफ़सेट देगा।

बेशक

, कि अगर फ़ाइल में परिवर्तन अक्सर, हालांकि आप नियंत्रित कर सकते हैं, तो क्या होता है जब चीजें संलग्न हो, आप अभी भी ऑफसेट सूचकांक को कुशलता से जोड़ सकते हैं ताकि उपयोगी नहीं है। यदि आप पर नियंत्रण नहीं करते हैं, तो आपको सूचकांक की अंतिम-संशोधित दिनांक मुख्य फ़ाइल की तुलना में पहले होने पर पुन: अनुक्रमणिका करना होगा।


और, अपने अद्यतन के आधार पर:

अद्यतन: यदि यह मायने रखती है, सभी लाइनें एक ही लंबाई की है।

जानकारी के उस अतिरिक्त टुकड़ा के साथ

, आप सूचकांक जरूरत नहीं है - रिकॉर्ड लंबाई द्वारा रिकॉर्ड लंबाई गुणा (यह मानते हुए मूल्यों में फिट से तुम सिर्फ मुख्य फ़ाइल में सही स्थान पर तुरंत प्राप्त कर सकते हैं अपने जानकारी का प्रकार)।

तो छद्म कोड की तरह कुछ:

def getline(fhandle,reclen,recnum): 
    seek to position reclen*recnum for file fhandle. 
    read reclen characters into buffer. 
    return buffer. 
+0

कैम के पास एक बेहतर समाधान है, लेकिन मैं इसे यहां ऐसे मामले के लिए छोड़ दूंगा जहां रिकॉर्ड निश्चित नहीं हैं। – paxdiablo

+0

इसके लिए धन्यवाद, बहुत जानकारीपूर्ण। – JavaRocky

14

head -10 file | tail -1 रिटर्न 10 शायद धीमी लाइन यद्यपि।

here

# print line number 52 
sed -n '52p' # method 1 
sed '52!d' # method 2 
sed '52q;d' # method 3, efficient on large files 
+0

जब आप लाइन 32696 की तलाश में हैं तो अधिक उपयोगी हो जाता है। – Amanda

2

एक अजीब विकल्प, जहां 3 लाइन संख्या है।

awk 'NR == 3 {print; exit}' file.txt 
+0

प्रिंट करने और बाहर निकलने के लिए बेहतर है, इसलिए अजीब फ़ाइल के बाकी हिस्सों से गुजरता नहीं है। – ghostdog74

+0

बहुत अच्छा बिंदु – Jamie

1

एक त्वरित पर्ल एक लाइनर यह भी के लिए अच्छी तरह से काम करेगा ...

$ perl -ne 'if (YOURLINENUMBER..YOURLINENUMBER) {print $_; last;}' /path/to/your/file 
2

sed साथ उपयोग q खोज रोक के बाद लाइन मुद्रित किया गया है बनाने के लिए।

sed -n '11723{p;q}' filename 

अजगर (कम से कम त्रुटि जाँच):

#!/usr/bin/env python 
import sys 

# by Dennis Williamson - 2010-05-08 
# for http://stackoverflow.com/questions/2794049/getting-one-line-in-a-huge-file-with-bash 

# seeks the requested line in a file with a fixed line length 

# Usage: ./lineseek.py LINE FILE 

# Example: ./lineseek 11723 data.txt 

EXIT_SUCCESS  = 0 
EXIT_NOT_FOUND = 1 
EXIT_OPT_ERR  = 2 
EXIT_FILE_ERR  = 3 
EXIT_DATA_ERR  = 4 

# could use a try block here 
seekline = int(sys.argv[1]) 

file = sys.argv[2] 

try: 
    if file == '-': 
     handle = sys.stdin 
     size = 0 
    else: 
     handle = open(file,'r') 
except IOError as e: 
    print >> sys.stderr, ("File Open Error") 
    exit(EXIT_FILE_ERR) 

try: 
    line = handle.readline() 
    lineend = handle.tell() 
    linelen = len(line) 
except IOError as e: 
    print >> sys.stderr, ("File I/O Error") 
    exit(EXIT_FILE_ERR) 

# it would be really weird if this happened 
if lineend != linelen: 
    print >> sys.stderr, ("Line length inconsistent") 
    exit(EXIT_DATA_ERR) 

handle.seek(linelen * (seekline - 1)) 

try: 
    line = handle.readline() 
except IOError as e: 
    print >> sys.stderr, ("File I/O Error") 
    exit(EXIT_FILE_ERR) 

if len(line) != linelen: 
    print >> sys.stderr, ("Line length inconsistent") 
    exit(EXIT_DATA_ERR) 

print(line) 

तर्क सत्यापन एक बहुत बेहतर होना चाहिए और कई अन्य सुधार के लिए जगह नहीं है।