बैश में एक फ़ाइल से अंतिम पंक्ति निकालें


330

मेरे पास एक फाइल है, foo.txt , जिसमें निम्नलिखित पंक्तियाँ हैं:

a
b
c

मैं एक साधारण आदेश चाहता हूं जिसके परिणामस्वरूप सामग्री होती है foo.txt:

a
b

जवाबों:


406

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

sed -i '$ d' foo.txt

-iविकल्प में मौजूद नहीं है GNU sed3.95 की तुलना में पुराने संस्करणों है, तो आप एक अस्थायी फ़ाइल के साथ एक फिल्टर के रूप में उपयोग करने के लिए है:

cp foo.txt foo.txt.tmp
sed '$ d' foo.txt.tmp > foo.txt
rm -f foo.txt.tmp

बेशक, उस मामले में आप के head -n -1बजाय भी इस्तेमाल कर सकते हैंsed

मैक ओ एस:

Mac OS X पर (10.7.4 के रूप में), sed -iऊपर दिए गए कमांड के बराबर है

sed -i '' -e '$ d' foo.txt

56
Mac OS X पर (10.7.4 के रूप में), sed -iऊपर दिए गए कमांड के बराबर है sed -i '' -e '$ d' foo.txt। इसके अलावा, head -n -1वर्तमान में एक मैक पर काम नहीं करेगा।
mklement0

26
क्या आप बता सकते हैं कि '$ d' रेगेक्स क्या करता है? यह अंतिम पंक्ति को हटाने के बारे में प्रश्न है, इसलिए मुझे लगता है कि यह प्रश्न देखने वाले सभी लोगों के लिए यह सबसे महत्वपूर्ण हिस्सा है। धन्यवाद :)
kravemir

38
@ मिरो: किसी भी तरह से $ dरेगेक्स नहीं है। यह एक sed कमांड है। dएक पंक्ति को हटाने का आदेश है, जबकि $"फ़ाइल में अंतिम पंक्ति" है। जब किसी कमांड से पहले किसी स्थान (सीड लिंगो में "रेंज" कहा जाता है) को निर्दिष्ट किया जाता है, तो उस कमांड को केवल निर्दिष्ट स्थान पर लागू किया जाता है। तो, यह कमांड स्पष्ट रूप से कहता है "एक फ़ाइल में अंतिम पंक्ति की सीमा में, इसे हटाएं"। यदि आप मुझसे पूछें तो बहुत ही सुस्त और सीधे मुद्दे पर।
डेनियल कामिल कोजार

1
आपकी अंतिम पंक्ति को कैसे हटाएं लेकिन केवल अगर यह एक खाली रेखा है?
स्केन

1
@ एलेक्स: जीएनयू सेड के लिए अपडेट किया गया; विभिन्न BSD / UNIX / MacOS sed संस्करणों के बारे में कोई विचार नहीं ...
thkala

279

यह अब तक का सबसे तेज और सरल उपाय है, खासकर बड़ी फाइलों पर:

head -n -1 foo.txt > temp.txt ; mv temp.txt foo.txt

यदि आप शीर्ष पंक्ति को हटाना चाहते हैं तो इसका उपयोग करें:

tail -n +2 foo.txt

जिसका अर्थ है लाइन 2 पर शुरू होने वाली आउटपुट लाइनें।

sedफ़ाइल के ऊपर या नीचे से लाइनें हटाने के लिए उपयोग न करें - यदि फ़ाइल बड़ी है तो यह बहुत धीमी है।


16
head -n -1 foo.txtपर्याप्त है
ДМИТРИЙ МАЛИКОВ

20
हेड -n -1 bdsutils के सिर पर काम नहीं करता है। कम से कम संस्करण में मैकोस उपयोग नहीं कर रहा है, इसलिए यह काम नहीं करता है।
johannes_lalala

23
@johannes_lalala मैक पर, आप brew install coreutils(GNU कोर उपयोगिताओं) कर सकते हैं और gheadइसके बजाय उपयोग कर सकते हैं head
दिलचस्प

बिल्ली TAILfixer: यहाँ एक सरल बैश स्क्रिप्ट मामले में यह automates आप नीचे लाइनों के विभिन्न संख्या के साथ एक से अधिक फ़ाइलों को हटाने के लिए है कि है FILE=$1; TAIL=$2; head -n -${TAIL} ${FILE} > temp ; mv temp ${FILE}myFile से उदाहरण के लिए 4 लाइनों को हटाने के रूप में के लिए भागो यह: ./TAILfixer myfile 4निश्चित रूप से पहले यह द्वारा निष्पादन योग्य बनानेchmod +x TAILfixer
FatihSarigol

अंगूठे क्योंकि यह काम किया था, लेकिन सभी की तुलना के लिए sed, इस आदेश के रूप में अच्छी तरह से बहुत धीमी गति से है
जेफ Diederiks

121

मुझे यहां सभी उत्तरों से परेशानी थी क्योंकि मैं एक बड़ी फ़ाइल (~ 300 जीबी) के साथ काम कर रहा था और कोई भी समाधान नहीं मिला। यहाँ मेरा समाधान है:

dd if=/dev/null of=<filename> bs=1 seek=$(echo $(stat --format=%s <filename> ) - $( tail -n1 <filename> | wc -c) | bc )

शब्दों में: उस फ़ाइल की लंबाई ज्ञात करें जिसे आप समाप्त करना चाहते हैं (इसकी अंतिम पंक्ति की लंबाई की फ़ाइल माइनस लंबाई, का उपयोग करके bc), और, उस स्थिति को फ़ाइल के अंत में सेट करें ( ddएक के बाइट द्वारा/dev/null पर यह)।

यह तेजी से है क्योंकि tailअंत से पढ़ना शुरू होता है, और जगह मेंdd फ़ाइल को अधिलेखित कर देगा प्रत्येक पंक्ति को कॉपी (और पार्स) के बजाय , जो कि अन्य समाधान करते हैं।

नोट: यह जगह में फ़ाइल से लाइन हटाता है! अपनी फ़ाइल को आज़माने से पहले डमी फ़ाइल पर बैकअप या परीक्षण करें!


3
मुझे dd के बारे में भी नहीं पता था। यह शीर्ष उत्तर होना चाहिए। आपको बहुत - बहुत धन्यवाद! यह शर्म की बात है कि समाधान gzipped फ़ाइलों के लिए (ब्लॉक) काम नहीं करता है।
tommy.carstensen

4
बहुत, बहुत चतुर दृष्टिकोण! बस एक नोट: इसे एक वास्तविक फ़ाइल की आवश्यकता होती है और संचालित होती है, इसलिए इसका उपयोग पाइप, कमांड सबस्टेशन, पुनर्निर्देशन और ऐसी श्रृंखलाओं पर नहीं किया जा सकता है।
MestreLion

3
यह शीर्ष उत्तर होना चाहिए। मेरी ~ 8 जीबी फ़ाइल के लिए तुरंत काम किया।
पीटर कॉगन

8
mac उपयोगकर्ता: dd if = / dev / null of = <filename> bs = 1 seek = $ (echo $ (stat -f =% z <filename> | cut -c 2-) - $ (tail -n1 <<enename> | wc -c) | bc)
इगोर

2
यह दृष्टिकोण बड़ी फ़ाइलों के लिए जाने का तरीका है!
thomas.han 5

61

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

tail -n 1 "$file" | wc -c | xargs -I {} truncate "$file" -s -{}

अंतिम पंक्ति को निकालने के लिए और इसे stdout पर प्रिंट करें ("पॉप" इट), आप उस कमांड को इसके साथ जोड़ सकते हैं tee:

tail -n 1 "$file" | tee >(wc -c | xargs -I {} truncate "$file" -s -{})

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

यदि आप इन्हें बार-बार उपयोग करने जा रहे हैं और त्रुटि से निपटने और कुछ अन्य सुविधाएँ चाहते हैं, तो आप poptailयहाँ कमांड का उपयोग कर सकते हैं: https://github.com/donm/evenmoreutils


3
त्वरित नोट: truncateडिफ़ॉल्ट रूप से OS X पर उपलब्ध नहीं है। लेकिन ब्रू का उपयोग करके इंस्टॉल करना आसान है brew install truncate:।
गिलाउम बुद्रेउ

3
बहुत अच्छा। Dd के बिना बहुत बेहतर है। मैं dd को एक एकल गलत अंक या अक्षर के रूप में उपयोग करने से
घबराया था

1
(जोकर चेतावनी) वास्तव में, ("dd" -> "आपदा") 1 प्रतिस्थापन और 6 सम्मिलन की आवश्यकता है; शायद ही "एक एकल गलत अंक या पत्र"। :)
काइल

29

मैक उपयोगकर्ता

अगर आप केवल आखिरी लाइन हटाए गए आउटपुट को फाइल में बदले बिना चाहते हैं

sed -e '$ d' foo.txt

यदि आप इनपुट फ़ाइल की अंतिम पंक्ति को स्वयं हटाना चाहते हैं

sed -i '' -e '$ d' foo.txt


यह मेरे लिए काम करता है लेकिन मुझे समझ नहीं आता। किसी भी तरह, यह काम किया।
मेल्विन

फ़्लैग -i ''फ़ाइल को इन-प्लेस में संशोधित करने के लिए sed को बताता है, जबकि एक फाइल में बैकअप को पैरामीटर के रूप में दिए गए एक्सटेंशन के साथ रखता है। चूंकि पैरामीटर एक खाली स्ट्रिंग है, इसलिए कोई बैकअप फ़ाइल नहीं बनाई गई है। -eकमांड को निष्पादित करने के लिए sed को बताता है। कमांड का $ dअर्थ है: अंतिम पंक्ति ( $) ढूंढें और इसे हटाएं ( d)।
Krzysztof Szafranek

24

मैक उपयोगकर्ताओं के लिए:

मैक पर, हेड-एन -1 अभ्यस्त काम। और, मैं केवल "सिर" और / या "पूंछ" कमांड का उपयोग करके इस समस्या को हल करने के लिए एक सरल समाधान [प्रसंस्करण समय की चिंता किए बिना] खोजने की कोशिश कर रहा था।

मैंने आदेशों के निम्नलिखित अनुक्रम की कोशिश की और खुश था कि मैं इसे "पूंछ" कमांड का उपयोग करके हल कर सकता था [मैक पर उपलब्ध विकल्पों के साथ]। इसलिए, यदि आप मैक पर हैं, और इस समस्या को हल करने के लिए केवल "पूंछ" का उपयोग करना चाहते हैं, तो आप इस कमांड का उपयोग कर सकते हैं:

बिल्ली file.txt | पूंछ -r | tail -n +2 | पूँछ -r

स्पष्टीकरण:

1> टेल-आर: बस इसके इनपुट में लाइनों के क्रम को उलट देता है

2> टेल-एन +2: यह अपने इनपुट में दूसरी लाइन से शुरू होने वाली सभी लाइनों को प्रिंट करता है


2
Homebrew का उपयोग कर coreutils स्थापित करना आपको 'के रूप में ghead' जीएनयू सिर दे देंगे, तो आप ऐसा करने की इजाजत दीghead -n -1
somewhatoff

13
echo -e '$d\nw\nq'| ed foo.txt

2
एक फ़िल्टर समाधान के लिए जो फ़ाइल को जगह में संपादित नहीं करता है, उपयोग करें sed '$d'
lhf

8
awk 'NR>1{print buf}{buf = $0}'

अनिवार्य रूप से, यह कोड निम्नलिखित कहता है:

पहली के बाद की प्रत्येक पंक्ति के लिए, बफ़र की गई पंक्ति को प्रिंट करें

प्रत्येक पंक्ति के लिए, बफर रीसेट करें

बफ़र एक पंक्ति से पिछड़ा हुआ है, इसलिए आप मुद्रण लाइनों को 1 से n-1 तक समाप्त करते हैं


2
यह समाधान एक फिल्टर है और जगह में फ़ाइल को संपादित नहीं करता है।
lhf


0

ये दोनों समाधान अन्य रूपों में यहां हैं। मुझे ये कुछ अधिक व्यावहारिक, स्पष्ट और उपयोगी लगे:

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

BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
dd if=${ORIGINALFILE} of=${ORIGINALFILE}.tmp status=none bs=1 count=$(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc )
/bin/mv -f ${ORIGINALFILE}.tmp ${ORIGINALFILE}

ट्रंकट का उपयोग करना:

BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
truncate -s $(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc ) ${ORIGINALFILE}

आउच। रास्ता बहुत जटिल है।
रॉबर्ट

0

लिनक्स

$ अंतिम पंक्ति है, डी को हटाने के लिए:

sed '$d' ~/path/to/your/file/name

मैक ओ एस

तलछट के समतुल्य -इ

sed -i '' -e '$ d' ~/path/to/your/file/name

0

यहां बताया गया है कि आप इसे मैन्युअल रूप से कैसे कर सकते हैं (मैं व्यक्तिगत रूप से इस पद्धति का बहुत उपयोग करता हूं जब मुझे फ़ाइल में अंतिम पंक्ति को जल्दी से हटाने की आवश्यकता होती है):

vim + [FILE]

+वहाँ उस संकेत का मतलब है कि जब फ़ाइल विम पाठ संपादक में खोली जाती है, तो कर्सर फ़ाइल की अंतिम पंक्ति पर स्थित होगा।

अब बस dअपने कीबोर्ड पर दो बार दबाएं । यह वही करेगा जो आप चाहते हैं - अंतिम पंक्ति को हटा दें। उसके बाद, प्रेस :द्वारा पीछा किया xऔर फिर प्रेस Enter। यह परिवर्तनों को बचाएगा और आपको शेल में वापस लाएगा। अब, अंतिम पंक्ति को सफलतापूर्वक हटा दिया गया है।


2
सादगी पर जोर यहाँ खो गया था
पीटर एम

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