यूनिक्स - सिर और फ़ाइल की पूंछ


131

कहो कि आपके पास एक txt फ़ाइल है, शीर्ष 10 लाइनों और फ़ाइल के निचले 10 लाइनों को एक साथ देखने के लिए क्या कमांड है?

यानी यदि फाइल 200 लाइनों की है, तो लाइनों को 1-10 और 190-200 में एक बार में देखें।


आपका क्या मतलब है "एक बार में"?
cnicutar 13

@cnicutar यानी। नहीं जा रहा सिर -10 फ़ाइल आंकड़ों को देखने के लिए अलग से और फिर पूंछ -10 फ़ाइल जा रहा है और आंकड़ों को देखने
Toop

@toop यदि आप एक वास्तविक कामकाजी उदाहरण चाहते हैं, तो stackoverflow.com/a/44849814/99834
sorin

जवाबों:


208

आप बस:

(head; tail) < file.txt

और अगर आपको किसी कारणवश पाइप का उपयोग करने की आवश्यकता है, तो इस तरह से करें:

cat file.txt | (head; tail)

नोट: डुप्लिकेट की गई लाइनों को प्रिंट करेगा यदि फ़ाइल में लाइनों की संख्या। txt सिर की डिफ़ॉल्ट लाइनों की तुलना में छोटी है + पूंछ की डिफ़ॉल्ट लाइनें।


54
कड़ाई से बोलते हुए, यह आपको मूल फ़ाइल की पूंछ नहीं देता है, लेकिन बाद की धारा headने फ़ाइल की पहली 10 पंक्तियों को खा लिया है। ( head < file.txt; tail < file.txt20 से कम लाइनों वाली फ़ाइल पर इसकी तुलना करें )। बस एक बहुत ही मामूली बात ध्यान में रखना है। (लेकिन फिर भी +1।)
शेपनर

15
अच्छा लगा। यदि आप सिर और पूंछ के हिस्सों के बीच एक अंतर चाहते हैं: (सिर; गूंज; पूंछ) <file.txt
सिमोन हिब्स

3
क्यों / यह कैसे काम करता है के बारे में उत्सुक। इसे एक नए प्रश्न के रूप में पूछा गया: stackoverflow.com/questions/13718242
zellyn

9
@nametal दरअसल, आपको शायद इतना भी न मिले। जबकि headकेवल इसके इनपुट की पहली 10 पंक्तियों को प्रदर्शित करता है, इस बात की कोई गारंटी नहीं है कि यह 10 वीं पंक्ति को समाप्त करने के लिए इसका अधिक उपभोग नहीं करता है , lessप्रदर्शन के लिए इनपुट के कम छोड़ देता है।
चेपनर

20
कहने के लिए क्षमा करें, लेकिन जवाब केवल कुछ मामलों में काम करता है। seq 100 | (head; tail)मुझे केवल पहले 10 नंबर देता है। केवल बहुत बड़े इनपुट आकार पर (जैसे seq 2000) पूंछ को कुछ इनपुट मिलता है।
मॉड्यूलर

18

ed है standard text editor

$ echo -e '1+10,$-10d\n%p' | ed -s file.txt

2
क्या होगा यदि फ़ाइल में 200 से अधिक लाइनें हों या कम हों? और आपको पता नहीं है कि initio में लाइनों की संख्या कितनी है?
पॉल

मैं बदल दिया है @Paul sedकोed
कीव

14

एक शुद्ध धारा (उदाहरण के लिए एक कमांड से आउटपुट) के लिए, आप 'टी' का उपयोग स्ट्रीम को कांटा करने के लिए कर सकते हैं और एक स्ट्रीम को हेड और एक को टेल पर भेज सकते हैं। इसके लिए या तो '> (सूची)' सुविधा का उपयोग करना आवश्यक है (+ / dev / fd / N):

( COMMAND | tee /dev/fd/3 | head ) 3> >( tail )

या जटिल पुनर्निर्देशन के साथ / dev / fd / N (या / dev / stderr) प्लस उप-भाग का उपयोग करना:

( ( seq 1 100 | tee /dev/fd/2 | head 1>&3 ) 2>&1 | tail ) 3>&1
( ( seq 1 100 | tee /dev/stderr | head 1>&3 ) 2>&1 | tail ) 3>&1

(इनमें से कोई भी csh या tsh में काम नहीं करेगा।)

थोड़ा बेहतर नियंत्रण के साथ कुछ के लिए, आप इस पर्ल कमांड का उपयोग कर सकते हैं:

COMMAND | perl -e 'my $size = 10; my @buf = (); while (<>) { print if $. <= $size; push(@buf, $_); if ( @buf > $size ) { shift(@buf); } } print "------\n"; print @buf;'

1
धारा समर्थन के लिए +1। आप stderr का पुन: उपयोग कर सकते हैं:COMMAND | { tee >(head >&2) | tail; } |& other_commands
jfs

2
btw, यह बफर साइज (मेरे सिस्टम पर 8K) से बड़ी फ़ाइलों के लिए टूटता है। cat >/dev/nullइसे ठीक करता है:COMMAND | { tee >(head >&2; cat >/dev/null) | tail; } |& other_commands
jfs

मुझे समाधान पसंद था, लेकिन आ के लिए खेलने के बाद जब मैंने देखा कि कुछ मामलों में पूंछ सिर से पहले चल रही थी ... कोई आदेश headऔर tailआदेशों के बीच कोई गारंटी नहीं है : \ ...
Jan

7
(sed -u 10q; echo ...; tail) < file.txt

(head;tail)थीम पर बस एक और भिन्नता है , लेकिन छोटी फ़ाइलों के लिए प्रारंभिक बफर भरण मुद्दे से बचना।


4

head -10 file.txt; tail -10 file.txt

इसके अलावा, आपको अपना कार्यक्रम / स्क्रिप्ट लिखने की आवश्यकता होगी।


1
अच्छा, मैंने हमेशा उपयोग किया है catऔर headया tailपाइप किया है, यह जानने के लिए अच्छा है कि मैं उन्हें व्यक्तिगत रूप से उपयोग कर सकता हूं!
पॉल

फिर मैं इन पहले 10 + अंतिम 10 को दूसरे कमांड में कैसे पाइप कर सकता हूं?
Toop

1
@ पाओल - 'your_program' के साथ wc -l के रूप में यह २० के बजाय १० लौटाता है
टॉप

3
या, बिना { head file; tail file; } | prog
उप-भाग

1
वाह ... लगभग दो वर्षों के बाद दूसरों के समान जवाब देने के लिए एक डाउन-वोट (फिर भी उनके सामने टाइमस्टैम्प्ड), किसी ऐसे व्यक्ति से जिसने पोस्ट नहीं किया कि वे डाउन-वोट क्यों करते हैं। अच्छा!
माह

4

जेएफ सेबेस्टियन की टिप्पणी पर आधारित :

cat file | { tee >(head >&3; cat >/dev/null) | tail; } 3>&1

इस तरह आप पहली पंक्ति और शेष को अलग-अलग एक पाइप में संसाधित कर सकते हैं, जो सीएसवी डेटा के साथ काम करने के लिए उपयोगी है:

{ echo N; seq 3;} | { tee >(head -n1 | sed 's/$/*2/' >&3; cat >/dev/null) | tail -n+2 | awk '{print $1*2}'; } 3>&1
एन * 2
2
4
6

3

यहाँ समस्या यह है कि स्ट्रीम-ओरिएंटेड प्रोग्राम फाइल की लंबाई पहले से नहीं जानते हैं (क्योंकि हो सकता है कि यह एक वास्तविक स्ट्रीम न हो)।

उपकरण की तरह tailपिछले n लाइनों देखा बफ़र और धारा के अंत के लिए प्रतीक्षा करें, फिर प्रिंट करें।

यदि आप इसे एक ही आदेश में करना चाहते हैं (और यह किसी भी ऑफसेट के साथ काम करता है, और लाइनों को दोहराना नहीं है अगर वे ओवरलैप करते हैं) तो आपको मेरे द्वारा बताए गए इस व्यवहार का अनुकरण करना होगा।

इस अजीब कोशिश:

awk -v offset=10 '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' yourfile

जब फ़ाइल फ़ाइल से बड़ी हो तो मुद्दों से बचने के लिए इसे और अधिक काम करने की आवश्यकता होती है
Samus_

याय, यह पाइप्ड आउटपुट के साथ काम करता है, न कि केवल फाइलों पर: a.out | awk -v ...
केमिली गौडेयुन

वास्तव में :) लेकिन यह जाग के सामान्य व्यवहार है, अधिकांश कमांडलाइन कार्यक्रम बिना किसी तर्क के आह्वान करने पर काम करते हैं।
Samus_

1
वांछित व्यवहार के बहुत करीब लेकिन ऐसा लगता है कि <10 लाइनों के लिए यह अतिरिक्त नई लाइनें जोड़ता है।
सोरिन

3

इस समाधान को समाप्त करने में बहुत समय लगा, जो ऐसा प्रतीत होता है कि सभी उपयोग मामलों को कवर किया गया है (अब तक):

command | tee full.log | stdbuf -i0 -o0 -e0 awk -v offset=${MAX_LINES:-200} \
          '{
               if (NR <= offset) print;
               else {
                   a[NR] = $0;
                   delete a[NR-offset];
                   printf "." > "/dev/stderr"
                   }
           }
           END {
             print "" > "/dev/stderr";
             for(i=NR-offset+1 > offset ? NR-offset+1: offset+1 ;i<=NR;i++)
             { print a[i]}
           }'

सुविधा की सूची:

  • सिर के लिए लाइव आउटपुट (जाहिर है कि पूंछ के लिए संभव नहीं है)
  • बाहरी फ़ाइलों का कोई उपयोग नहीं
  • MAX_LINES के बाद प्रत्येक पंक्ति के लिए एक बिंदु के रूप में प्रगति पट्टी, लंबे समय तक चलने वाले कार्यों के लिए बहुत उपयोगी है।
  • स्टोडर पर प्रगतिबार, यह विश्वास दिलाता है कि प्रगति डॉट्स को सिर + पूंछ से अलग किया जाता है (यदि आप डीडी को पाइप करना चाहते हैं तो बहुत आसान है)
  • बफरिंग (stdbuf) के कारण संभावित गलत लॉगिंग ऑर्डर से बचा जाता है
  • जब आउटपुट की कुल संख्या हेड + टेल से छोटी हो तो डुप्लिकेट आउटपुट से बचें।

2

मैं कुछ समय के लिए इस समाधान के लिए देख रहा हूँ। इसे स्वयं सेड के साथ करने की कोशिश की, लेकिन पहले से फ़ाइल / स्ट्रीम की लंबाई न जानने की समस्या लाज़मी थी। उपरोक्त सभी विकल्पों में से, मुझे केमिली गौडेय्यून के जाग समाधान पसंद हैं। उन्होंने यह नोट किया कि उनके समाधान ने पर्याप्त रूप से छोटे डेटा सेट के साथ आउटपुट में अतिरिक्त रिक्त लाइनें छोड़ दीं। यहां मैं उनके समाधान का एक संशोधन प्रदान करता हूं जो अतिरिक्त लाइनों को हटा देता है।

headtail() { awk -v offset="$1" '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { a_count=0; for (i in a) {a_count++}; for (i=NR-a_count+1; i<=NR; i++) print a[i] }' ; }

1

खैर, आप हमेशा उन्हें एक साथ चेन कर सकते हैं। , इसलिए चाहते head fiename_foo && tail filename_foo। यदि यह पर्याप्त नहीं है, तो आप अपनी .profile फ़ाइल या आपके द्वारा उपयोग की जाने वाली किसी भी लॉगिन फ़ाइल में अपने आप को एक bash फ़ंक्शन लिख सकते हैं:

head_and_tail() {
    head $1 && tail $1
}

और, बाद में इसे अपने शेल प्रॉम्प्ट से मंगवाएं head_and_tail filename_foo:।


1

पहले 10 लाइनें file.ext, फिर इसकी आखिरी 10 लाइनें:

cat file.ext | head -10 && cat file.ext | tail -10

फ़ाइल की अंतिम 10 लाइनें, फिर पहले 10:

cat file.ext | tail -10 && cat file.ext | head -10

फिर आप आउटपुट को कहीं और भी पाइप कर सकते हैं:

(cat file.ext | head -10 && cat file.ext | tail -10 ) | your_program


5
जब आप सिर्फ हेड -10 file.txt कॉल कर सकते हैं तो कैट का उपयोग क्यों करें?
jstarek

क्या आप लाइनों की संख्या को परिवर्तनशील बना सकते हैं, इसलिए कॉल कुछ इस प्रकार है: हेड_ टेल (foo, m, n) - पाठ की पहली m snd अंतिम n लाइनों को वापस करना?
रिकाडर्ड

@ricardo जिसमें एक बैश स्क्रिप्ट लिखना शामिल है जो 3 आर्ग लेती है और उन्हें अलिया-इंग द्वारा एक फ़ंक्शन tailऔर headया एक फ़ंक्शन में भेजती है ।
पॉल

1

मैंने ऐसा करने के लिए एक साधारण अजगर ऐप लिखा: https://gist.github.com/garyvdm/9970522

यह पाइप (धाराओं) के साथ-साथ फाइलों को भी संभालता है।


2
कोड के संबंधित भागों को पोस्ट करना सबसे अच्छा होगा।
फेडोरक्वी 'SO रोकना नुकसान पहुँचाता है'

1

ऊपर दिए गए विचारों पर ड्राइंग

लेकिन एक उपनाम 'टोपी' सिर और पूंछ का उपयोग कर

alias hat='(head -5 && echo "^^^------vvv" && tail -5) < '


hat large.sql

0

sedइस कार्य के लिए उपयोग क्यों नहीं ?

sed -n -e 1,+9p -e 190,+9p textfile.txt


3
यह ज्ञात लंबाई की फ़ाइलों के लिए काम करता है, लेकिन उन फ़ाइलों के लिए नहीं जिनकी लंबाई अज्ञात है।
केविन

0

फ़ाइलों के साथ-साथ पाइप (स्ट्रीम) को संभालने के लिए, इसे अपनी .bashrc या .profile फ़ाइल में जोड़ें।

headtail() { awk -v offset="$1" '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' ; }

तब आप ही नहीं कर सकते

headtail 10 < file.txt

लेकिन

a.out | headtail 10

(यह अभी भी स्पष्ट रिक्त लाइनों को लागू करता है जब 10 इनपुट की लंबाई से अधिक होता है, सादे पुराने के विपरीत a.out | (head; tail)। धन्यवाद, पिछले उत्तरदाताओं।)

नोट: headtail 10नहीं headtail -10


0

@Aleksandra Zalcman की कमांड कैसे काम करती है, इस बारे में @Samus_ ने यहां बताया कि यह भिन्नता तब आसान है जब आप जल्दी से उस स्थान पर नहीं पहुंच सकते जहां पूंछ बिना लाइनों की गिनती के शुरू होती है।

{ head; echo "####################\n...\n####################"; tail; } < file.txt

या यदि आप 20 लाइनों के अलावा किसी अन्य चीज से काम करना शुरू करते हैं, तो एक पंक्ति गणना भी मदद कर सकती है।

{ head -n 18; tail -n 14; } < file.txt | cat -n

0

किसी फ़ाइल की पहली 10 और अंतिम 10 पंक्तियों को प्रिंट करने के लिए, आप यह कोशिश कर सकते हैं:

cat <(head -n10 file.txt) <(tail -n10 file.txt) | less


0
sed -n "1,10p; $(( $(wc -l ${aFile} | grep -oE "^[[:digit:]]+")-9 )),\$p" "${aFile}"

नोट : aFile वैरिएबल में फ़ाइल का पूर्ण पथ है


0

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

यहां बताया गया है कि हाल ही में मैंने कितनी बड़ी CSV फ़ाइलों का विश्लेषण किया था, जिनका मैं विश्लेषण कर रहा था:

$ for file in *.csv; do echo "### ${file}" && head ${file} && echo ... && tail ${file} && echo; done

यह प्रत्येक फ़ाइल के पहले 10 लाइनों और अंतिम 10 लाइनों को प्रिंट करता है, जबकि फ़ाइल नाम और कुछ दीर्घवृत्त को प्रिंट करने से पहले और बाद में भी।

एक बड़ी फ़ाइल के लिए, आप बस उसी प्रभाव के लिए निम्नलिखित चला सकते हैं:

$ head somefile.csv && echo ... && tail somefile.csv

0

स्टड का उपभोग करता है, लेकिन सरल और उपयोग के मामलों के 99% के लिए काम करता है

head_and_tail

#!/usr/bin/env bash
COUNT=${1:-10}
IT=$(cat /dev/stdin)
echo "$IT" | head -n$COUNT
echo "..."
echo "$IT" | tail -n$COUNT

उदाहरण

$ seq 100 | head_and_tail 4
1
2
3
4
...
97
98
99
100
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.