एक ही फ़ाइल में लाइनों के विभिन्न सेट और बचत को हथियाने के लिए सिर और पूंछ का उपयोग करना


10

तो यह होमवर्क के लिए है, लेकिन मैं विशिष्ट होमवर्क प्रश्न नहीं पूछूंगा।

मुझे एक फ़ाइल से लाइन के विभिन्न सेटों को हथियाने के लिए सिर और पूंछ का उपयोग करने की आवश्यकता है। तो लाइन्स 6-11 और लाइन्स 19-24 की तरह और उन दोनों को एक और फाइल में सेव करें। मुझे पता है कि मैं इस तरह के रूप में इस का उपयोग कर सकते हैं

head -11 file|tail -6 > file1; head -24 file| tail -6 >> file1. 

लेकिन मुझे नहीं लगता कि हम करने वाले हैं।
क्या कोई विशिष्ट तरीका है जिससे मैं सिर और पूंछ कमांड को जोड़ सकता हूं और फिर फाइल को बचा सकता हूं?


1
क्या वे विशेष रूप से आपको उपयोग करने के लिए कह रहे हैं headऔर tail? यदि हां, तो आपका समाधान बहुत अच्छा है जो आप कर सकते हैं। यदि आपको अन्य कार्यक्रमों का उपयोग करने की अनुमति है, sedया awkअच्छे समाधानों के लिए अनुमति दे सकते हैं (यानी कम प्रक्रिया चालान के साथ)।
n.st

हाँ, वे हमारे लिए सिर और पूंछ का उपयोग करने के लिए कह रहे हैं। आपके उत्तर के लिए धन्यवाद।
user2709291

एक और चीज जो मैं जोड़ सकता हूं: आप >>अपने सुरीले आउटपुट को पुनर्निर्देशित करने के लिए कोष्ठक में दो आदेशों को संलग्न करके अपग्रेडिंग आउटपुट पुनर्निर्देशन ( ) के आसपास प्राप्त कर सकते हैं (head -11 file | tail -6; head -24 file | tail -6) > file1:। यह वास्तव में व्यक्तिगत पसंद के लिए नीचे आता है जो कि अच्छा है।
n.st

आपका धन्यवाद कि बहुत अच्छा काम करेंगे। मैं वास्तव में इसकी प्रशंसा करता हूँ।
user2709291

जवाबों:


11

आप इसे headअकेले और बुनियादी अंकगणित के साथ कर सकते हैं , यदि आप समूह { ... ; }जैसे निर्माण का उपयोग करने की आज्ञा देते हैं

{ head -n ...; head -n ...; ...; } < input_file > output_file

जहां सभी कमांड समान इनपुट साझा करते हैं (धन्यवाद @mikeserv )।
लाइनों 6-11 और लाइनों 19-24 के बराबर है:

head -n 5 >/dev/null  # dump the first 5 lines to `/dev/null` then
head -n 6             # print the next 6 lines (i.e. from 6 to 11) then
head -n 7 >/dev/null  # dump the next 7 lines to `/dev/null` ( from 12 to 18)
head -n 6             # then print the next 6 lines (19 up to 24)

तो, मूल रूप से, आप दौड़ेंगे:

{ head -n 5 >/dev/null; head -n 6; head -n 7 >/dev/null; head -n 6; } < input_file > output_file

यह मेरे लिए काम नहीं करता है। इनपुट पहले सिर से enterily सेवन किया जाता है
Whimusical

6

आप { … }कंपाउंड कमांड पर रिडायरेक्शन ऑपरेटर को लागू करने के लिए ग्रुपिंग कंस्ट्रक्शन का उपयोग कर सकते हैं ।

{ head -n 11 file | tail -n 6; head -n 24 file | tail -n 6; } >file1

पहली M + N लाइनों को डुप्लिकेट करने और केवल अंतिम N को रखने के बजाय, आप पहली M लाइनों को छोड़ सकते हैं और अगले N को डुप्लिकेट कर सकते हैं। यह बड़ी फ़ाइलों पर औसत रूप से तेज़ है । इस बात से सावधान रहें कि +Nतर्क का tailअर्थ है कि छोड़ देने के लिए लाइनों की संख्या नहीं है, लेकिन एक प्लस - यह पहली पंक्ति की संख्या है जिसे 1 से गिने जाने वाली लाइनों के साथ प्रिंट करना है।

{ tail -n +6 file | head -n 6; tail -n +19 file | head -n 6; } >file1

किसी भी तरह से, आउटपुट फ़ाइल को केवल एक बार खोला जाता है, लेकिन इनपुट फ़ाइल को निकालने के लिए प्रत्येक स्निपेट के लिए एक बार ट्रेस किया जाता है। इनपुट को समूहीकृत करने के बारे में कैसे?

{ tail -n +6 | head -n 6; tail -n +14 | head -n 6; } <file >file1

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

एक अन्य दृष्टिकोण लाइनों को छोड़ने के लिए headपाइप्ड का उपयोग करना /dev/nullहै।

{ head -n 5 >/dev/null; head -n 6; head -n 7 >/dev/null; head -n 6; } <file >file1

फिर, यह बफरिंग के कारण काम करने की गारंटी नहीं है। यह headGNU कोरुटिल्स (गैर-एम्बेडेड लिनक्स सिस्टम पर पाया जाने वाला) से कमांड के साथ काम करने के लिए होता है , जब इनपुट एक नियमित फ़ाइल से होता है। ऐसा इसलिए है क्योंकि एक बार इस कार्यान्वयन headने जो चाहा पढ़ा है, वह फ़ाइल स्थिति को पहले बाइट के लिए सेट करता है जो इसे आउटपुट नहीं करता था। यदि इनपुट पाइप है तो यह काम नहीं करता है।

एक फ़ाइल से लाइनों के कई दृश्यों को प्रिंट करने का एक सरल तरीका एक अधिक सामान्यवादी उपकरण जैसे कि sed या awk को कॉल करना है । (यह धीमा हो सकता है, लेकिन यह केवल बहुत बड़ी फ़ाइलों के लिए मायने रखता है।)

sed -n -e '6,11p' -e '19,24p' <file >file1
sed -e '1,5d' -e '12,18d' -e '24q' <file >file1
awk '6<=NR && NR<=11 || 19<=NR && NR<=24' <file >file1
awk 'NR==6, NR==11; NR==19, NR==24' <file >file1

2
यह काम करने के लिए नहीं होता है, यह मानक, निर्दिष्ट व्यवहार है - हालांकि निश्चित रूप से, जैसा कि आप कहते हैं, एक पाइप साझा इनपुट के लिए एक विश्वसनीय इनपुट स्रोत नहीं है। उपयोगिता विवरण : जब कोई मानक उपयोगिता किसी खोजे जाने योग्य इनपुट फ़ाइल को पढ़ती है और अंतिम-फ़ाइल तक पहुँचने से पहले बिना किसी त्रुटि के समाप्त हो जाती है, तो उपयोगिता यह सुनिश्चित करेगी कि फ़ाइल के खुले विवरण में ऑफसेट फ़ाइल ठीक से पिछले बाइट द्वारा संसाधित की गई है उपयोगिता।
मिकसेर्व

2

मुझे पता है कि आपने कहा था कि आपको सिर और पूंछ का उपयोग करने की आवश्यकता है, लेकिन निश्चित रूप से यहां नौकरी के लिए sed सरल उपकरण है।

$ cat foo
a 1 1
a 2 1
b 1 1
a 3 1
c 3 1
c 3 1
$ sed -ne '2,4p;6p' foo
a 2 1
b 1 1
a 3 1
c 3 1

तुम भी कुछ अन्य प्रक्रिया के साथ एक स्ट्रिंग में ब्लॉकों का निर्माण कर सकते हैं और इसे सेड के माध्यम से चला सकते हैं।

$ a="2,4p;6p"
$ sed -ne $a foo
a 2 1
b 1 1
a 3 1
c 3 1

-एन आउटपुट को नकारता है, तो आप पी के साथ प्रिंट करने के लिए पर्वतमाला निर्दिष्ट करते हैं, अल्पविराम द्वारा अलग की गई पहली और अंतिम संख्या के साथ।

कहा जा रहा है, आप या तो कमांडिंग ग्रुपिंग कर सकते हैं जो @don_crissti ने सुझाव दिया है, या फाइल के माध्यम से कुछ समय के लिए लूप को सिर / पूंछ के साथ हर बार जब आप जाते हैं तो लाइनों का एक हिस्सा हड़प सकते हैं।

$ head -4 foo | tail -3; head -6 foo | tail -1
a 2 1
b 1 1
a 3 1
c 3 1

एक फ़ाइल में जितनी अधिक लाइनें और आपके पास जितने अधिक ब्लॉक होंगे, उतनी ही अधिक कुशल सेड मिलेगी।


2

sedतुम्हारे साथ हो सकता है:

sed '24q;1,5d;12,18d' <infile >outfile

... संभवतः एक अधिक कुशल समाधान के साथ किया जा सकता था head। डॉन ने पहले ही प्रदर्शित कर दिया है कि यह कैसे बहुत अच्छा काम कर सकता है, लेकिन मैं इसके साथ भी खेल रहा हूं। इस विशिष्ट मामले को संभालने के लिए आप कुछ कर सकते हैं:

for   n in 5 6 7 6
do    head -n"$n" >&"$((1+n%2))"
done  <infile >outfile 2>/dev/null

... जो head4 बार या तो लिखने के लिए outfileया /dev/nullइस बात पर निर्भर करता है कि क्या पुनरावृत्ति का मूल्य $nएक सम या विषम संख्या है।

अधिक सामान्य मामलों के लिए, मैंने इसे कुछ अन्य सामानों से एक साथ सिल दिया था जो मेरे पास पहले से थे:

somehead()( 
### call it like:
### somehead -[repeat] [-][numlines]* <infile >outfile
    set -e -- "${1#-}" "$@"                             #-e for arg validation
    r=; cd -- "${TMP:-/tmp}"                            #go to tmp
    dd bs=4096 of="$$$$" <&4 2>&3 &                     #dd <in >tmpfile &bg
    until [ -s "$$$$" ]; do :; done                     #wait while tmpfile empty
    exec <"$$$$" 4<&-;   rm "$$$$"                      #<tmpfile; rm tmpfile
    [ "$3${1}0" -ne "$3${2#?}0" ]          ||           #validate args - chk $1
            shift "$(((r=-${1:--1})||1))"; shift        #shift 1||2
    while [ "$(((r+=(_n=1))-1))" -ne 0 ]   &&           #while ! $rptmax &&
          IFS= read -r l                   &&           #      ! EOF     &&
          printf "%.$(($1>0?${#l}+1:0))s" "$l           #      ? printf  do
";  do    for n do [ "${n#-}" -gt 0 ]      || exit      #args all -[nums>0]
          head "-n$((${n#-}-_n))" >&"$((n>(_n=0)?1:3))" #head -n?$1 >?[+-]
    done; done                                          #done and done
)   4<&0 3>/dev/null                                    #4<for dd 3>for head

यह आपकी बात कर सकता है जैसे:

 seq 100 | somehead -1 -5 6 -7 6

... जो प्रिंट करता है ...

6
7
8
9
10
11
19
20
21
22
23
24

यह उम्मीद करता है कि इसका पहला arg एक बार के साथ उपसर्ग दोहराए जाने की गिनती हो -, या, असफल होकर , बस एक -। यदि कोई गणना प्रदान की जाती है, तो यह निम्न आर्गनों में दी गई लाइन पैटर्न को कई बार निर्दिष्ट करेगी और जैसे ही उसने ऐसा किया है, रुक जाएगी।

प्रत्येक arg के लिए जो इसका अनुसरण करता है एक लाइन-काउंट को इंगित करने के लिए एक नकारात्मक पूर्णांक की व्याख्या करेगा, जिसे लिखा जाना चाहिए /dev/nullऔर एक पॉज़िट काउंट को इंगित करने के लिए एक पॉज़िटिव काउंटर जिसे लिखा जाना चाहिए stdout

इसलिए उपरोक्त उदाहरण में यह पहली 5 पंक्तियों को /dev/null, अगली 6 को stdout, अगली 7 को /dev/nullफिर से और अगली 6 को एक बार फिर से प्रिंट करता है stdout। अपने आर्ग्स के अंतिम तक पहुंच गया और -1रिपीट काउंट के माध्यम से पूरी तरह से साइकिल चलाने के बाद, वह फिर से चलता है। यदि पहला अर्ग -2होता तो यह प्रक्रिया को एक बार और दोहराया जाता, या जब -तक यह हो सकता था।

प्रत्येक आर्ग चक्र के लिए whileलूप को एक बार के माध्यम से संसाधित किया जाता है। प्रत्येक लूप के शीर्ष पर stdinशेल लाइन में से पहली पंक्ति को पढ़ा जाता है $l। यह आवश्यक है क्योंकि while head </dev/null; do :; doneअनिश्चित काल तक दोहराया जाएगा - headइसकी वापसी में संकेत मिलता है जब यह फ़ाइल के अंत तक पहुंच गया है। इसलिए ईओएफ के खिलाफ चेक समर्पित है readऔर केवल एक नई रूपरेखा printfलिखेगा यदि दूसरा तर्क एक सकारात्मक पूर्णांक है।$lstdout

readजांच पाश एक छोटे से पेचीदा हो क्योंकि तुरंत बाद एक और पाश कहा जाता है - एक forपाश जो आर्ग से अधिक iterates 2-$#में प्रतिनिधित्व के रूप में $nअपनी मूल के प्रत्येक यात्रा के लिए whileपाश। इसका मतलब यह है कि प्रत्येक पुनरावृत्ति के लिए पहले arg को कमांड लाइन पर निर्दिष्ट मान से एक से घटाया जाना चाहिए, लेकिन अन्य सभी को अपने मूल मानों को बनाए रखना चाहिए, और इसलिए $_nमार्कर var का मान प्रत्येक से घटाया जाता है, लेकिन कभी-कभी एक मान रखता है पहले arg के लिए 0 से अधिक मूल्य।

यह फ़ंक्शन के मुख्य लूप का गठन करता है, लेकिन कोड का थोक शीर्ष पर है और इसका उद्देश्य फ़ंक्शन को इनपुट के रूप में एक पाइप से भी साफ बफर करने में सक्षम करना है। यह पहली बार dd4k के एक टुकड़े के उत्पादन पर एक tmpfile में अपनी कॉपी करने के लिए एक पृष्ठभूमि को बुलाकर काम करता है । फ़ंक्शन तब एक होल्ड लूप सेट करता है - जिसे लगभग कभी भी एक पूर्ण चक्र पूरा नहीं करना चाहिए - बस यह सुनिश्चित करने के लिए कि ddफ़ंक्शन से पहले फ़ाइल में कम से कम एक ही लिखना है फिर अपने स्टड को एक फ़ाइल विवरणक के साथ बदल देता है जिसे tmpfile से जोड़ा गया है और बाद में तुरंत फ़ाइल को अनलिंक कर देता हैrm। यह फ़ंक्शन को मज़बूती से ट्रैप की आवश्यकता के बिना या क्लीनअप के लिए स्ट्रीम को संसाधित करने में सक्षम बनाता है - जैसे ही फ़ंक्शन जारी करता है यह fd पर दावा करता है tmpfile मौजूद नहीं रहेगा क्योंकि इसका एकमात्र नामित फ़ाइल सिस्टम लिंक पहले ही हटा दिया गया है।


0

इस तरह से एक बश फ़ंक्शन का उपयोग करें:

seq 1 30 > input.txt
f(){ head $1 input.txt | tail $2 >> output.txt ;}; f -11 -2; f -24 -3
cat output.txt
10
11
22
23
24

यह इस मामले में थोड़ा अधिक है, लेकिन यदि आपके फ़िल्टर बड़े होते हैं तो यह एक वरदान बन सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.