मैं यूनिक्स पर एक पाठ फ़ाइल से लाइनों की एक पूर्व निर्धारित सीमा कैसे निकाल सकता हूं?


531

मेरे पास एक ~ 23000 लाइन एसक्यूएल डंप है जिसमें डेटा के कई डेटाबेस हैं। मुझे इस फ़ाइल का एक निश्चित भाग (यानी एक डेटाबेस के लिए डेटा) निकालने और इसे एक नई फ़ाइल में रखने की आवश्यकता है। मुझे उस डेटा के आरंभ और अंत पंक्ति संख्याओं की जानकारी है जो मुझे चाहिए।

क्या कोई व्यक्ति यूनिक्स कमांड (या कमांड की श्रृंखला) को फाइल लाइन 16224 और 16482 के बीच की सभी लाइनों को निकालने के लिए कहता है और फिर उन्हें एक नई फाइल में रीडायरेक्ट करता है?


जब से तुम बड़ी फ़ाइलों का उल्लेख है, मैं देखने का सुझाव देते टिप्पणी stackoverflow.com/questions/83329/...
sancho.s ReinstateMonicaCellio

जवाबों:


792
sed -n '16224,16482p;16483q' filename > newfile

से sed मैनुअल :

पी - पैटर्न स्पेस (मानक आउटपुट पर) प्रिंट करें। यह आदेश आमतौर पर केवल एन-कमांड लाइन विकल्प के साथ संयोजन में उपयोग किया जाता है।

n - यदि ऑटो-प्रिंट अक्षम नहीं है, तो पैटर्न स्पेस प्रिंट करें, फिर, चाहे, पैटर्न स्पेस को इनपुट की अगली लाइन से बदलें। यदि कोई और इनपुट नहीं है तो sed बिना किसी और कमांड को प्रोसेस किए बाहर निकल जाता है।

q - sedकिसी भी अधिक कमांड या इनपुट को संसाधित किए बिना बाहर निकलें । ध्यान दें कि यदि ऑटो प्रिंट को एन विकल्प के साथ अक्षम नहीं किया गया है तो वर्तमान पैटर्न स्पेस प्रिंट किया गया है।

तथा

एक सीड स्क्रिप्ट में पते निम्न में से किसी भी रूप में हो सकते हैं:

the एक लाइन नंबर निर्दिष्ट करना इनपुट में केवल उस रेखा से मेल खाएगा।

एक पता श्रेणी को अल्पविराम (,) द्वारा अलग किए गए दो पतों को निर्दिष्ट करके निर्दिष्ट किया जा सकता है। एक पता श्रेणी उन रेखाओं से मेल खाती है जहां से पहला पता मेल खाता है, और दूसरे पते के मिलान (समावेशी) तक जारी रहता है।


3
मैं उत्सुक था अगर यह मूल फ़ाइल को संशोधित करता है। मैंने इसे केवल मामले में बैक अप किया है और ऐसा प्रतीत होता है कि इसने मूल को संशोधित नहीं किया, जैसा कि अपेक्षित था।
एंडी ग्रॉफ

@AndyGroff। फ़ाइल को "-i" पैरामीटर के उपयोग के लिए संशोधित करने के लिए। अन्यथा यह फ़ाइल को संशोधित नहीं करेगा।
youri

175
यदि, मेरी तरह, आपको बहुत बड़ी फ़ाइल पर ऐसा करने की आवश्यकता है, तो यह मदद करता है यदि आप अगली पंक्ति में एक कमांड छोड़ते हैं। तो फिर यह है sed -n '16224,16482p;16483q' filename। अन्यथा sed अंत तक स्कैनिंग रखेगा (या कम से कम मेरा संस्करण करता है)।
WDS

7
@ माइल राउत लोग पूछते दिखते हैं "डाउनवोट क्यों?" बहुत बार, शायद आपका मतलब है "मुझे परवाह नहीं है" के बजाय "कोई परवाह नहीं करता"
मार्क

1
@wds - आपकी टिप्पणी एक उत्तर के योग्य है जो शीर्ष पर चढ़ती है। यह दिन और रात के बीच अंतर कर सकता है।
sancho.s ReinstateMonicaCellio

203
sed -n '16224,16482 p' orig-data-file > new-file

जहां 16224,16482 स्टार्ट लाइन नंबर और एंड लाइन नंबर, समावेशी हैं। यह 1-अनुक्रमित है। -nइनपुट को आउटपुट के रूप में प्रतिध्वनित करता है, जिसे आप स्पष्ट रूप से नहीं चाहते हैं; संख्या निम्न कमांड को चालू करने के लिए लाइनों की सीमा को दर्शाती है; कमांड pसंबंधित पंक्तियों को प्रिंट करता है।


7
बड़ी फ़ाइलों पर, इच्छित आदेश मिलने के बाद उपरोक्त कमांड पूरी फ़ाइल को चलना जारी रखेगा। क्या रेंज आउटपुट होने के बाद फ़ाइल को संसाधित करने के लिए sed रोकना एक तरीका है?
गैरी

39
खैर, यहां जवाब से , ऐसा लगता है कि सीमा के अंत में रुकने के साथ पूरा किया जा सकता है sed -n '16224,16482p;16482q' orig-data-file > new-file:।
गैरी

5
आप एक अनावश्यक स्थान में क्यों डालेंगे, और फिर बोली होगी? (बेशक, अनावश्यक समस्याएँ बनाना और उन्हें हल करना कंप्यूटर विज्ञान के आधे हिस्से का सार है, लेकिन मेरा मतलब है कि इस कारण से ...)
कज़

92

काफी आसान सिर / पूंछ का उपयोग कर:

head -16482 in.sql | tail -258 > out.sql

sed का उपयोग करना:

sed -n '16482,16482p' in.sql > out.sql

awk का उपयोग करना:

awk 'NR>=10&&NR<=20' in.sql > out.sql

1
दूसरा और तीसरा विकल्प ठीक है, लेकिन पहला कई विकल्पों की तुलना में धीमा है क्योंकि यह 2 कमांड का उपयोग करता है जहां 1 पर्याप्त है। इसके लिए सही तर्क प्राप्त करने के लिए गणना की भी आवश्यकता होती है tail
जोनाथन लेफ़लर

3
यह देखते हुए कि प्रश्न के समान लाइन नंबरों को रखने के लिए, sed कमांड होनी चाहिए sed -n 16224,16482p' in.sql >out.sqlऔर awk कमांड होनी चाहिएawk 'NR>=16224&&NR<=16482' in.sql > out.sql
sibaz

3
यह भी जानने के लायक है कि पहले उदाहरण के मामले में head -16482 in.sql | tail -$((16482-16224)) >out.sqlगणना को
कोसने के

1
सिर और पूंछ के साथ पहला वाला तेजी से बड़े संस्करणों पर बड़ी तेजी से सी-विकल्प के साथ, सी-विकल्प के साथ जोड़ा गया। हेड-वर्जन इंस्टेंट और सेड वर्जन I Ctrl-C एक मिनट के बाद ... धन्यवाद
मियागी

2
tail -n +16224संगणना कम करने के लिए भी उपयोग कर सकते हैं
SOFe

35

आप 'vi' और फिर निम्न कमांड का उपयोग कर सकते हैं:

:16224,16482w!/tmp/some-file

वैकल्पिक रूप से:

cat file | head -n 16482 | tail -n 258

EDIT: - केवल स्पष्टीकरण जोड़ने के लिए, आप पहले 16482 लाइनों को प्रदर्शित करने के लिए 16482 हेड का उपयोग करते हैं और फिर पहले आउटपुट से आखिरी 258 लाइनों को प्राप्त करने के लिए टेल -n 258 का उपयोग करते हैं।


2
और vi के बजाए आप ex का उपयोग कर सकते हैं, वह vi माइनस इंटरैक्टिव कंसोल स्टफ है।
तदेउस्ज़ ए। कदलोबोस्की

1
आपको catआज्ञा की आवश्यकता नहीं है ; headसीधे एक फ़ाइल पढ़ सकते हैं। यह कई विकल्पों की तुलना में धीमा है क्योंकि यह 2 (3 दिखाए अनुसार) कमांड का उपयोग करता है जहां 1 पर्याप्त है।
जोनाथन लेफ़लर

1
@JonathanLeffler आप काफी गलत हैं। यह धधक रहा है। मैं 200k लाइन्स निकालता हूं, 1G के बारे में, 2G फाइल से 500k लाइनों के साथ, कुछ सेकंड में (बिना cat)। अन्य समाधानों को कम से कम कुछ मिनटों की आवश्यकता होती है। इसके अलावा जीएनयू पर सबसे तेज बदलाव दिखता है tail -n +XXX filename | head XXX
एंटोनियो क्रिस्टोफ़ाइड्स

28

इसके साथ एक और दृष्टिकोण है awk:

awk 'NR==16224, NR==16482' file

यदि फ़ाइल बहुत बड़ी है, तो exitअंतिम वांछित पंक्ति को पढ़ने के बाद यह अच्छा हो सकता है । इस तरह, यह अनावश्यक रूप से निम्नलिखित पंक्तियों को नहीं पढ़ेगा:

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file

awk 'NR==16224, NR==16482; NR==16482 {exit}' file

2
उपयोग करके रनटाइम और संसाधनों को बचाने के लिए 1+ print; exit। धन्यवाद !
बर्नी रेइटर

2 उदाहरण का थोड़ा सरलीकरण:awk 'NR==16224, NR==16482; NR==16482 {exit}' file
रॉबिन ए। मीड

वह उज्ज्वल है, धन्यवाद @ रॉबिन.मैड! मैंने आपके विचार को पोस्ट में संपादित किया
फेडोरक्वी 'एसओ स्टॉप हार्मिंग'


9
 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2

6
cat dump.txt | head -16224 | tail -258

चाल चलनी चाहिए। इस दृष्टिकोण का नकारात्मक पक्ष यह है कि आपको पूंछ के तर्क को निर्धारित करने के लिए अंकगणित को करने की आवश्यकता है और यह ध्यान रखें कि आप 'के बीच' को अंतिम पंक्ति में शामिल करना चाहते हैं या नहीं।


4
आपको catआज्ञा की आवश्यकता नहीं है ; headसीधे एक फ़ाइल पढ़ सकते हैं। यह कई विकल्पों की तुलना में धीमा है क्योंकि यह 2 (3 दिखाए अनुसार) कमांड का उपयोग करता है जहां 1 पर्याप्त है।
जोनाथन लेफ़लर

@JonathanLeffler यह उत्तर पढ़ने और याद रखने में सबसे आसान है। यदि आप वास्तव में प्रदर्शन के बारे में परवाह करते हैं तो आप पहली बार एक शेल का उपयोग नहीं कर रहे होंगे। विशिष्ट साधनों को एक निश्चित कार्य के लिए खुद को समर्पित करने देना अच्छा अभ्यास है। इसके अलावा, "अंकगणित" का उपयोग करके हल किया जा सकता है | tail -$((16482 - 16224))
यति १

6

Boxxar के कंधों पर खड़े होकर, मुझे यह पसंद है:

sed -n '<first line>,$p;<last line>q' input

जैसे

sed -n '16224,$p;16482q' input

$"अंतिम लाइन" का मतलब है, इसलिए पहला कमांड sedलाइन से शुरू होने वाली सभी लाइनों को प्रिंट करता है 16224और दूसरा कमांड प्रिंटिंग लाइन के बादsed छोड़ देता है । ( बॉक्सएक्सार के समाधान में व्यवस्था को जोड़ना आवश्यक प्रतीत नहीं होता है।)164281q

मुझे यह संस्करण पसंद है क्योंकि मुझे दो बार समाप्त होने वाली पंक्ति संख्या निर्दिष्ट करने की आवश्यकता नहीं है। और मैंने मापा कि $प्रदर्शन पर हानिकारक प्रभाव नहीं है।



3

जल्दी और गन्दी:

head -16428 < file.in | tail -259 > file.out

शायद इसे करने का सबसे अच्छा तरीका नहीं है लेकिन यह काम करना चाहिए।

BTW: 259 = 16482-16224 + 1।


यह कई विकल्पों की तुलना में धीमा है क्योंकि यह 2 कमांड का उपयोग करता है जहां 1 पर्याप्त है।
जोनाथन लेफ़लर

3

मैंने स्प्लिटर नामक एक हास्केल कार्यक्रम लिखा जो ठीक यही करता है: मेरी रिलीज ब्लॉग पोस्ट के माध्यम से पढ़ा है

आप कार्यक्रम का उपयोग इस प्रकार कर सकते हैं:

$ cat somefile | splitter 16224-16482

और यही सब कुछ है। इसे स्थापित करने के लिए आपको हास्केल की आवश्यकता होगी। बस:

$ cabal install splitter

और आप कर रहे हैं। मुझे उम्मीद है कि आपको यह कार्यक्रम उपयोगी लगेगा।


क्या splitterकेवल मानक इनपुट से पढ़ा जाता है? एक मायने में, इससे कोई फर्क नहीं पड़ता; यह catआदेश उत्कृष्ट है कि यह करता है या नहीं। या तो उपयोग करें splitter 16224-16482 < somefileया (यदि यह फ़ाइल नाम तर्क लेता है) splitter 16224-16482 somefile
जोनाथन लेफ़लर

3

यहां तक ​​कि हम कमांड लाइन पर जांच करने के लिए भी ऐसा कर सकते हैं:

cat filename|sed 'n1,n2!d' > abc.txt

उदाहरण के लिए:

cat foo.pl|sed '100,200!d' > abc.txt

6
आपको catइन दोनों में से किसी की भी आवश्यकता नहीं है ; sedअपने दम पर फ़ाइलों को पढ़ने में पूरी तरह से सक्षम है, या आप एक फ़ाइल से मानक इनपुट को पुनर्निर्देशित कर सकते हैं।
जोनाथन लेफ़लर


2

मैं हेड / टेल ट्रिक पोस्ट करने वाला था, लेकिन वास्तव में मैं शायद सिर्फ एमएसीएस फायर करूंगा। ;-)

  1. esc- xगोटो-लाइन ret16224
  2. चिह्न ( ctrl- space)
  3. esc- xगोटो-लाइन ret16482
  4. esc-w

नई आउटपुट फ़ाइल खोलें, ctl-y सहेजें

मुझे देखने दो कि क्या हो रहा है।


4
Emacs मेरे अनुभव में बहुत बड़ी फ़ाइलों पर बहुत अच्छा प्रदर्शन नहीं करता है।
ग्रेग मैट

क्या आप इसे स्क्रिप्टेड एक्शन के रूप में चला सकते हैं, या यह केवल एक इंटरैक्टिव विकल्प है?
जोनाथन लेफ़लर

2

मै इस्तेमाल करूंगा:

awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt

FNR में फ़ाइल से पढ़ी जा रही लाइन का रिकॉर्ड (लाइन) नंबर होता है।


2

मैं एक चर का उपयोग कर स्क्रिप्ट से एक ही काम करना चाहता था और चर नाम को p से अलग करने के लिए $ चर के आसपास उद्धरण लगाकर इसे प्राप्त किया:

sed -n "$first","$count"p imagelist.txt >"$imageblock"

मैं एक सूची को अलग-अलग फ़ोल्डरों में विभाजित करना चाहता था और प्रारंभिक प्रश्न पाया और एक उपयोगी कदम का जवाब दिया। (विभाजित कमांड पुराने ओएस पर एक विकल्प नहीं है जिसे मुझे पोर्ट कोड करना है)।


1

मैंने एक छोटी बैश स्क्रिप्ट लिखी है जिसे आप अपनी कमांड लाइन से चला सकते हैं, इसलिए जब तक आप अपनी निर्देशिका को शामिल करने के लिए अपने PATH को अपडेट करते हैं (या आप इसे उस निर्देशिका में रख सकते हैं जो पहले से ही PATH में समाहित है)।

उपयोग: $ चुटकी फ़ाइलनाम प्रारंभ-लाइन अंत-पंक्ति

#!/bin/bash
# Display line number ranges of a file to the terminal.
# Usage: $ pinch filename start-line end-line
# By Evan J. Coon

FILENAME=$1
START=$2
END=$3

ERROR="[PINCH ERROR]"

# Check that the number of arguments is 3
if [ $# -lt 3 ]; then
    echo "$ERROR Need three arguments: Filename Start-line End-line"
    exit 1
fi

# Check that the file exists.
if [ ! -f "$FILENAME" ]; then
    echo -e "$ERROR File does not exist. \n\t$FILENAME"
    exit 1
fi

# Check that start-line is not greater than end-line
if [ "$START" -gt "$END" ]; then
    echo -e "$ERROR Start line is greater than End line."
    exit 1
fi

# Check that start-line is positive.
if [ "$START" -lt 0 ]; then
    echo -e "$ERROR Start line is less than 0."
    exit 1
fi

# Check that end-line is positive.
if [ "$END" -lt 0 ]; then
    echo -e "$ERROR End line is less than 0."
    exit 1
fi

NUMOFLINES=$(wc -l < "$FILENAME")

# Check that end-line is not greater than the number of lines in the file.
if [ "$END" -gt "$NUMOFLINES" ]; then
    echo -e "$ERROR End line is greater than number of lines in file."
    exit 1
fi

# The distance from the end of the file to end-line
ENDDIFF=$(( NUMOFLINES - END ))

# For larger files, this will run more quickly. If the distance from the
# end of the file to the end-line is less than the distance from the
# start of the file to the start-line, then start pinching from the
# bottom as opposed to the top.
if [ "$START" -lt "$ENDDIFF" ]; then
    < "$FILENAME" head -n $END | tail -n +$START
else
    < "$FILENAME" tail -n +$START | head -n $(( END-START+1 ))
fi

# Success
exit 0

1
यह कई विकल्पों की तुलना में धीमा है क्योंकि यह 2 कमांड का उपयोग करता है जहां 1 पर्याप्त है। वास्तव में, यह wcकमांड के कारण फाइल को दो बार पढ़ता है , जो डिस्क बैंडविड्थ को बर्बाद करता है, खासकर गीगाबाइट फाइलों पर। सभी प्रकार के तरीकों में, यह अच्छी तरह से प्रलेखित है, लेकिन यह इंजीनियरिंग ओवरकिल भी है।
जोनाथन लेफ़लर

1

यह आपके लिए काम कर सकता है (GNU sed):

sed -ne '16224,16482w newfile' -e '16482q' file

या बैश का लाभ लेना:

sed -n $'16224,16482w newfile\n16482q' file

1

एड का उपयोग करना:

ed -s infile <<<'16224,16482p'

-sनैदानिक ​​उत्पादन को दबाता है; वास्तविक कमांड यहां एक स्ट्रिंग में हैं। विशेष रूप से, वांछित लाइन पता सीमा पर प्रिंट (प्रिंट) कमांड 16224,16482pचलाता है p


0

स्वीकार जवाब में काम करते हैं। आपके द्वारा झुकाव के मामले में यहां एक और तरीका है।

cat $filename | sed "${linenum}p;d";

यह निम्न कार्य करता है:

  1. एक फ़ाइल की सामग्री में पाइप (या पाठ में फ़ीड हालांकि आप चाहते हैं)।
  2. sed दी गई रेखा का चयन करता है, उसे प्रिंट करता है
  3. d को लाइनों को हटाने की आवश्यकता है, अन्यथा sed मान जाएगा कि सभी लाइनें अंततः मुद्रित हो जाएंगी। अर्थात, d के बिना, आपको चयनित लाइन द्वारा दो बार छपी हुई सभी पंक्तियाँ मिलेंगी क्योंकि आपके पास $ {linenum} p हिस्सा है जो इसे मुद्रित करने के लिए कहता है। मुझे पूरा यकीन है कि एन-एन मूल रूप से यहां डी के समान ही काम कर रहा है।

3
नोट cat file | sedमें बेहतर लिखा गया हैsed file
फेडोरक्वी 'एसओ स्टॉप हॉर्मिंग'

इसके अलावा यह सिर्फ एक रेखा को प्रिंट करता है, जबकि सवाल उनमें से एक श्रेणी के बारे में है।
फेडोरक्वी 'एसओ

0

चूंकि हम एक टेक्स्ट फ़ाइल से टेक्स्ट की लाइनों को निकालने के बारे में बात कर रहे हैं, इसलिए मैं एक विशेष मामला दूंगा जहां आप एक निश्चित पैटर्न से मेल खाने वाली सभी लाइनों को निकालना चाहते हैं।

myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile

[डेटा] लाइन और शेष प्रिंट करेगा। यदि आप लाइन 1 से पैटर्न पर पाठ चाहते हैं, तो आप टाइप करें: sed -n '1, / Data / p' myfile। इसके अलावा, यदि आप दो पैटर्न जानते हैं (बेहतर अपने पाठ में अद्वितीय हो), तो रेंज की शुरुआत और अंत दोनों को मैचों के साथ निर्दिष्ट किया जा सकता है।

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