2017-06-30 7 views
5

मेरे पास एक लॉग फ़ाइल है (एक ग्राहक से)। 18 गीगा फ़ाइल की सभी सामग्री 1 लाइन में हैं। मैं लॉगस्टैश में फ़ाइल को पढ़ना चाहता हूं। लेकिन मुझे मेमोरी की वजह से समस्याएं आती हैं। फ़ाइल लाइन से लाइन पढ़ी जाती है लेकिन दुर्भाग्यवश यह 1 लाइन पर है।प्रत्येक} को एक विशाल (12 जीबी) में एक} n के साथ बदलें जिसमें 1 लाइन होती है?

मैंने कोशिश की }\n साथ की जगह लाइनों में फ़ाइल विभाजित ताकि logstash यह (फ़ाइल एक सरल json प्रारूप, कोई नेस्टेड वस्तुएं हैं) को संसाधित कर सकते हैं मैं एक पंक्ति, बंटवारे में प्रत्येक json करना चाहते थे } पर:

sed -i 's/}/}\n/g' NonPROD.log.backup 

लेकिन sed मारे गए - मुझे स्मृति की वजह से भी लगता है। मैं इसे कैसे हल करूं? क्या मैं sed लाइनों की तुलना में डेटा के अन्य हिस्सों का उपयोग करके फ़ाइल में हेरफेर कर सकता हूं? मुझे डिफ़ॉल्ट रूप से पता है sed लाइन से लाइन पढ़ता है।

+2

तुम एक स्ट्रीमिंग फैशन में अपनी फ़ाइल पर कार्रवाई करने के 'jq' उपयोग करने पर विचार कर सकते हैं। – chepner

उत्तर

6

निम्नलिखित केवल खोल में निर्मित कार्यक्षमता का उपयोग करता:

#!/bin/bash 

# as long as there exists another } in the file, read up to it... 
while IFS= read -r -d '}' piece; do 
    # ...and print that content followed by '}' and a newline. 
    printf '%s}\n' "$piece" 
done 

# print any trailing content after the last } 
[[ $piece ]] && printf '%s\n' "$piece" 

आप logstash एक TCP पोर्ट (नीचे एक मनमाना उदाहरण के रूप में 14321 का प्रयोग करके) से पढ़ने के लिए कॉन्फ़िगर किया गया है, तो आप thescript <NonPROD.log.backup >"/dev/tcp/127.0.0.1/14321" या इसी तरह की है, और चला सकते हैं वहां आप हैं - डिस्क पर उपलब्ध आपकी मूल इनपुट फ़ाइल की जगह को दोगुना करने की आवश्यकता के बिना, अन्य उत्तरों को अब तक की आवश्यकता है।

1

आप किए जा सकेंगे:

  1. स्प्लिट फ़ाइल 1M हिस्सा कहने के लिए split -b 1m file.log
  2. प्रक्रिया का उपयोग कर सभी फाइलों को sed 's/}/}\n/g' x*
  3. ... और उन्हें एक टुकड़े के लिए वापस गठबंधन करने के लिए sed के उत्पादन अनुप्रेषित

इसकी कमी दोगुनी संग्रहण स्थान है।

+1

डबल्ड स्टोरेज होने जा रहा है इससे कोई फर्क नहीं पड़ता कि क्या कोई डिस्क पर आउटपुट को क्रमबद्ध करना चाहता है और ट्रांसफॉर्म किए जाने वाले ट्रांसफॉर्म को मूल इनपुट से बड़ा उत्पादन उत्पन्न होता है - जबकि 'sed -i' एक अस्थायी आउटपुट लिख रहा है, तो आउटपुट को जाने की आवश्यकता है * कहीं*। कोई वास्तव में इन-प्लेस ट्रांसफॉर्म केवल तभी कर सकता है जब आउटपुट बराबर आकार या छोटा हो। यदि आपने 'विभाजन' के रूप में जल्द ही मूल फ़ाइल को हटा दिया है, तो आप डबल + 1 एमबी (साथ ही साथ अतिरिक्त न्यूलाइन के आकार) पर जाने से बच सकते हैं। –

+0

(...अच्छी तरह से - "केवल" थोड़ा मजबूत था - लिनक्स में कुछ एक्सटेंशन हैं जो मेमोरी-मैप किए गए फ़ाइल में विशिष्ट ब्लॉक को हटाए जाने के लिए हटाए जाते हैं और उचित फाइल सिस्टम का उपयोग करते हुए स्पैस बनाते हैं, लेकिन यह काफी कोने का मामला है)। –

2

आप tr के माध्यम से इसे चलाने कर सकते हैं, तो प्रत्येक पंक्ति के अंत में पीठ पर अंत ब्रैकेट डाल:

$ cat NonPROD.log.backup | tr '}' '\n' | sed 's/$/}/' > tmp$$ 
$ wc -l NonPROD.log.backup tmp$$ 
    0 NonPROD.log.backup 
    43 tmp10528 
    43 total 

(मेरे परीक्षण फ़ाइल केवल 43 कोष्ठक था।)

+0

सरल, लेकिन यह काम करता है (फाइल के अंत में एक अतिरिक्त '}' डालने के अलावा अगर वहां पहले से कोई नहीं है)। मैं पाइपलाइन से 'बिल्ली' को लेने का सुझाव दूंगा - '

+0

इसे थक गया - समय में लगभग 1% की कमी आई। – Jack

+1

यूप। यदि प्रोग्राम 'सॉर्ट' जैसा कुछ है तो यह एक बड़ा अंतर होगा जो एक फीफो के साथ फ्रंट-टू-बैक पढ़ने की आवश्यकता के बजाय एक खोजने योग्य फ़ाइल हैंडल दिए जाने पर समानांतर हो सकता है। ('cat file |' 'file' तक सीधे पहुंच प्रदान नहीं करता है, लेकिन केवल 'cat' से आउटपुट स्ट्रीम करने के लिए)। एक और उदाहरण 'wc -c' है - वास्तविक फ़ाइल हैंडल के साथ यह निरंतर समय में समाप्त हो सकता है इससे कोई फर्क नहीं पड़ता कि फ़ाइल कितनी बड़ी है, फीफो के साथ इसे पूरी तरह से बिना शर्त पढ़ना है। –

0

RT के लिए जीएनयू awk साथ fold

$ fold -w 1000 long_line_file | sed 's/}/}\n\n/g' | tr -s '\n' 
+0

आपको उन स्थानों पर न्यूलाइन मिलती है जहां आपको उनकी आवश्यकता नहीं होती है। –

3

के साथ एक और विकल्प:

$ printf 'abc}def}ghi\n' | awk -v RS='}' -v ORS='}\n' 'NR>1{print p} {p=$0} END{printf "%s",p}' 
abc} 
def} 
ghi 

मैं वर्तमान में तैनात समाधान के सभी परीक्षण करने का फैसला:

$ printf 'abc}def}ghi\n' | awk -v RS='}' '{ORS=(RT?"}\n":"")}1' 
abc} 
def} 
ghi 
अन्य awks साथ

एक इनपुट फाइल का उपयोग कर कार्यक्षमता और निष्पादन समय के लिए इस आदेश के द्वारा उत्पन्न ई:

awk 'BEGIN{for(i=1;i<=1000000;i++)printf "foo}"; print "foo"}' > file1m 

और यहाँ है कि मैं क्या मिला:

time awk -v RS='}' '{ORS=(RT?"}\n":"")}1' file1m 

उम्मीद गया उत्पादन, समय =

:

1) awk (दोनों awk स्क्रिप्ट ऊपर इसी तरह के परिणाम) था

real 0m0.608s 
user 0m0.561s 
sys  0m0.045s 

2) shell loop:

$ cat tst.sh 
#!/bin/bash 

# as long as there exists another } in the file, read up to it... 
while IFS= read -r -d '}' piece; do 
    # ...and print that content followed by '}' and a newline. 
    printf '%s}\n' "$piece" 
done 

# print any trailing content after the last } 
[[ $piece ]] && printf '%s\n' "$piece" 

$ time ./tst.sh < file1m 

उम्मीद गया उत्पादन, समय =

real 1m52.152s 
user 1m18.233s 
sys  0m32.604s 

3) tr+sed:

$ time tr '}' '\n' < file1m | sed 's/$/}/' 

उम्मीद निर्गम (जोड़ी एक अवांछनीय } फ़ाइल के अंत में) का उत्पादन नहीं किया था, समय =

real 0m0.577s 
user 0m0.468s 
sys  0m0.078s 

एक ट्वीक इसके साथ ही अंतिम अवांछनीय } दूर करने के लिए:

$ time tr '}' '\n' < file1m | sed 's/$/}/; $s/}//' 

real 0m0.718s 
user 0m0.670s 
sys  0m0.108s 

4) fold+sed+tr:

$ time fold -w 1000 file1m | sed 's/}/}\n\n/g' | tr -s '\n' 

उम्मीद गया उत्पादन, समय =

real 0m0.811s 
user 0m1.137s 
sys  0m0.076s 

5) split+sed+cat:

$ cat tst2.sh 
mkdir tmp$$ 
pwd="$(pwd)" 
cd "tmp$$" 
split -b 1m "${pwd}/${1}" 
sed -i 's/}/}\n/g' x* 
cat x* 
rm -f x* 
cd "$pwd" 
rmdir tmp$$ 

$ time ./tst2.sh file1m 

उम्मीद गया उत्पादन, समय =

real 0m0.983s 
user 0m0.685s 
sys  0m0.167s 
संबंधित मुद्दे