मैं किसी फ़ाइल की सामग्री को n बार कैसे दोहरा सकता हूं?


19

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

केवल परीक्षणों को दोहराने के बजाय मैं इनपुट डेटा को कई बार डुप्लिकेट करना चाहूंगा (उदाहरण के लिए 1000) इसलिए एक 3 लाइन फ़ाइल 3000 लाइनें बन जाती है और मैं बहुत अधिक पूर्ण परीक्षण चला सकता हूं।

मैं फ़ाइल नाम से इनपुट डेटा पास कर रहा हूं:

mycommand input-data.txt

जवाबों:


21

आप की जरूरत नहीं है input-duplicated.txt

प्रयत्न:

mycommand <(perl -0777pe '$_=$_ x 1000' input-data.txt)

व्याख्या

  • 0777: -0सेट इनपुट रिकॉर्ड सेपरेटर (पर्ल विशेष चर $/जो डिफ़ॉल्ट रूप से एक नई रेखा है) सेट करता है । इससे अधिक मान पर सेट करने से 0400पर्ल पूरी इनपुट फ़ाइल को मेमोरी में खिसका देगा।
  • pe: -pइसका मतलब है " -eइसके द्वारा दी गई स्क्रिप्ट को लागू करने के बाद प्रत्येक इनपुट लाइन को प्रिंट करें "।
  • $_=$_ x 1000: $_वर्तमान इनपुट लाइन है। चूंकि हम पूरी फ़ाइल को एक साथ पढ़ रहे हैं -0700, इसलिए इसका अर्थ है पूरी फ़ाइल। x 1000में पूरी फ़ाइल के 1000 प्रतियां मुद्रित किया जा रहा परिणाम देगा।

अच्छा लगा। यह मूर्खता-व्रत है। 1000 xargs के लिए 0.785s, इसके लिए 0.006s, तो हाँ, शायद ओवरहेड मुद्दों को खत्म करता है जो मैं अपने लूप के साथ देख रहा था।
ओली

और 100000 गुना तक उछलकर केवल .002 से रनटाइम बढ़ता है। यह बहुत अद्भुत है।
ओली

@ ओली: छोटी फ़ाइलों के साथ, और आपके पास पर्याप्त मेमोरी है, perlइतना कुशल है, इसे इसके लिए डिज़ाइन किया गया है।
congonglm

11

मैं मूल रूप से सोच रहा था कि मुझे एक माध्यमिक फ़ाइल बनानी होगी, लेकिन मैं बस मूल फ़ाइल को बैश में लूप कर सकता हूं और इसे फ़ाइल के रूप में प्रकट करने के लिए कुछ पुनर्निर्देशन का उपयोग कर सकता हूं।

लूप करने के शायद एक दर्जन अलग-अलग तरीके हैं लेकिन यहाँ चार हैं:

mycommand <( seq 1000 | xargs -i -- cat input-data.txt )
mycommand <( for _ in {1..1000}; do cat input-data.txt; done )
mycommand <((for _ in {1..1000}; do echo input-data.txt; done) | xargs cat )
mycommand <(awk '{for(i=0; i<1000; i++)print}' input-data.txt)  #*

तीसरी विधि नीचे maru की टिप्पणी से सुधारित है और बिल्ली के लिए इनपुट फाइलनाम की एक बड़ी सूची बनाती है। xargsइस प्रणाली को अनुमति देगा के रूप में कई तर्कों में विभाजित करेगा। यह n अलग बिल्लियों की तुलना में बहुत तेज है ।

जिस awkतरह से ( टेर्डन के उत्तर से प्रेरित ) शायद सबसे अधिक अनुकूलित है लेकिन यह एक बार में प्रत्येक पंक्ति को डुप्लिकेट करता है। यह किसी विशेष एप्लिकेशन के अनुरूप हो सकता है या नहीं भी हो सकता है, लेकिन यह तेज़ और कुशल है।


लेकिन यह मक्खी पर उत्पन्न हो रहा है। बैश आउटपुट बहुत अधिक धीमी गति से होने की संभावना है जिससे कुछ पढ़ सकते हैं इसलिए आपको परीक्षण के लिए एक नई फ़ाइल तैयार करनी चाहिए। शुक्र है कि यह केवल एक बहुत ही सरल विस्तार है:

(for _ in {1..1000}; do echo input-data.txt; done) | xargs cat > input-duplicated.txt
mycommand input-duplicated.txt

3
आपके दोनों आदेशों में बिल्ली के चलने का समय है। क्या बिल्ली को एक बार चलाना और एक बार एन तर्क देने के लिए अधिक कुशल नहीं होगा? कुछ इस तरह cat $(for i in {1..N}; do echo filename; done)। इसमें आरजी आकार की सीमा है, लेकिन तेज होना चाहिए।
मुरु

@ मरमू अच्छा विचार भी। कुछ काम की जरूरत है लेकिन मैं इसे जोड़ दूंगा। वर्तमान कार्यान्वयन ~ लाइन में 7-लाइन फ़ाइल के 1000 पुनरावृत्तियों को कर रहा है। यह वास्तव में मेरे संस्करणों से बहुत बेहतर है, लेकिन Gnouc के पर्ल स्तर पर नहीं।
ओली

6

यहाँ एक awkसमाधान है:

awk '{a[NR]=$0}END{for (i=0; i<1000; i++){for(k in a){print a[k]}}}' file 

यह अनिवार्य रूप से @ Gnuc के पर्ल के रूप में उपवास है (मैं दोनों 1000 बार भागा और औसत समय मिला):

$ for i in {1..1000}; do 
 (time awk '{a[NR]=$0}END{for (i=0;i<1000;i++){for(k in a){print a[k]}}}' file > a) 2>&1 | 
    grep -oP 'real.*?m\K[\d\.]+'; done | awk '{k+=$1}END{print k/1000}'; 
0.00426

$ for i in {1..1000}; do 
  (time perl -0777pe '$_=$_ x 1000' file > a ) 2>&1 | 
    grep -oP 'real.*?m\K[\d\.]+'; done | awk '{k+=$1}END{print k/1000}'; 
0.004076

1
निष्पक्षता में, आप शायद awk '{for(i=0; i<1000; i++)print}' input-data.txtइसे सरल बना सकते हैं, इसलिए यह एक बार में प्रत्येक पंक्ति की 1000 प्रतियां जारी करता है। सभी अवसरों के अनुरूप नहीं है, लेकिन इससे भी तेज, कम देरी और पूरी फ़ाइल को रैम में रखने की आवश्यकता नहीं है।
ओली

@ वास्तव में, मैंने मान लिया था कि आप लाइन क्रम को बनाए रखना चाहते थे, इसलिए 123123123ठीक 111222333था लेकिन ऐसा नहीं था। आपका संस्करण स्पष्ट रूप से Gnouc की तुलना में तेज़ है, यह 0.00297 सेकंड में औसत है। संपादित करें: खरोंच, मैंने एक गलती की, यह वास्तव में 0.004013 सेकंड के बराबर है।
टेराडॉन

5

मैं सिर्फ एक पाठ संपादक का उपयोग करेगा।

vi input-data.txt
gg (move cursor to the beginning of the file)
yG (yank til the end of the file)
G (move the cursor to the last line of the file)
999p (paste the yanked text 999 times)
:wq (save the file and exit)

यदि आपको कमांड-लाइन के माध्यम से इसे करने की आवश्यकता है (इसके लिए आपको vimस्थापित करने की आवश्यकता है, जैसा viकि :normalकमांड नहीं है ), आप उपयोग कर सकते हैं:

vim -es -u NONE "+normal ggyGG999p" +wq input-data.txt

यहां, -es(या -e -s) vim को चुपचाप संचालित करता है, इसलिए इसे आपकी टर्मिनल विंडो पर नहीं ले जाना चाहिए, और -u NONEइसे आपके vimrc को देखने से रोकता है, जिससे इसे थोड़ा तेज चलना चाहिए, अन्यथा यह (शायद बहुत तेजी से, यदि आप उपयोग करते हैं) बहुत सारे vim plugins)।


हां, लेकिन यह सभी मैनुअल है जो इसे परिमाण के कई क्रमों को धीमा बनाता है और अन्य समाधानों की तुलना में अधिक जटिल है।
टेराडन

4

यहाँ एक साधारण लाइनर है, जिसमें कोई स्क्रिप्टिंग शामिल नहीं है:

mycommand <(cat `yes input-data.txt | head -1000 | paste -s`)

व्याख्या

  • `yes input-data.txt | head -1000 | paste -s`input-data.txt1000 बार सफेद स्थान से अलग पाठ का उत्पादन करता है
  • पाठ को तब catएक फ़ाइल सूची के रूप में पारित किया जाता है

यह समाधान काम नहीं करता है। क्या आपको उपयोग करने की आवश्यकता है xargs paste -s? यह काम करता है, लेकिन इनपुट फ़ाइल में नए सिरे को संरक्षित नहीं करता है।
जेरेमीकन

सुनिश्चित करें कि आप सही एपोस्ट्रोफ का उपयोग कर रहे हैं।
18

2

पूरी तरह से अलग स्क्रिप्ट पर काम करते हुए, मैंने सीखा है कि 29% लाइनों के साथ, टेक्स्ट का उपयोग करना seek()और डेटा का उपयोग करना अक्सर लाइन-बाय-लाइन आधार की तुलना में तेज़ होता है। नीचे दी गई स्क्रिप्ट में समान विचार लागू किया जाता है: हम फ़ाइल खोलते हैं, और फ़ाइल खोलने और बंद करने के माध्यम से लूपिंग के बजाय (जो ओवरहेड जोड़ सकते हैं, भले ही महत्वपूर्ण न हो), हम फ़ाइल को खुला रखते हैं और शुरुआत में वापस चाहते हैं।

#!/usr/bin/env python3
from __future__ import print_function
import sys,os

def error_out(string):
    sys.stderr.write(string+"\n")
    sys.exit(1)

def read_bytewise(fp):
    data = fp.read(1024)
    print(data.decode(),end="",flush=True)
    while data:
        data = fp.read(1024)
        print(data.decode(),end="",flush=True)
    #fp.seek(0,1)

def main():
    howmany = int(sys.argv[1]) + 1
    if not os.path.isfile(sys.argv[2]):
       error_out("Needs a valid file") 

    fp = open(sys.argv[2],'rb')
    for i in range(1,howmany):
        #print(i)
        fp.seek(0)
        read_bytewise(fp)
    fp.close()

if __name__ == '__main__': main()

स्क्रिप्ट ही उपयोग में काफी सरल है:

./repeat_text.py <INT> <TEXT.txt>

3 पंक्ति पाठ फ़ाइल और 1000 पुनरावृत्ति के लिए यह बिल्कुल ठीक है, लगभग 0.1 सेकंड:

$ /usr/bin/time ./repeat_text.py 1000 input.txt  > /dev/null                                                             
0.10user 0.00system 0:00.23elapsed 45%CPU (0avgtext+0avgdata 9172maxresident)k
0inputs+0outputs (0major+1033minor)pagefaults 0swaps

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


1

हम इसे अतिरिक्त फ़ाइल के बिना हल कर सकते हैं, न ही विशेष कार्यक्रम, शुद्ध बैश (अच्छी तरह से, बिल्ली एक मानक कमांड है)।

बैश के अंदर प्रिंटफ की एक विशेषता के आधार पर हम एक दोहराया स्ट्रिंग उत्पन्न कर सकते हैं):

printf "test.file.txt %.0s\n" {1..1000}

फिर, हम 1000 फ़ाइल नाम (बार-बार) और कॉल कैट की ऐसी सूची भेज सकते हैं:

printf "test.file.txt %.0s" {1..1000} | xargs cat 

और अंत में, हम कमांड को निष्पादित करने के लिए आउटपुट दे सकते हैं:

mycommand "$( printf "%.0sinput.txt\n" {1..1000} | xargs cat )"

या, यदि कमांड को इनपुट में इनपुट प्राप्त करने की आवश्यकता है:

mycommand < <( printf "%.0sinput.txt\n" {1..1000} | xargs cat )

हां, डबल <की जरूरत है।


0

मैं लूप के लिए यूनिक्स का उपयोग करके एक नई फ़ाइल उत्पन्न करूंगा:

content=$(cat Alex.pgn); for i in {1..900000}; do echo "$content" >> new_file; done 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.