मैं बैश में एक अनुगामी न्यूलाइन कैसे हटा सकता हूं?


10

मैं एक ऐसी चीज की तलाश कर रहा हूं जो पर्ल की तरह व्यवहार करती है chomp। मैं एक कमांड की तलाश कर रहा हूं जो कि इसके इनपुट को प्रिंट करता है, अगर यह एक नई रेखा है तो अंतिम वर्ण को घटा देता है:

$ printf "one\ntwo\n" | COMMAND_IM_LOOKING_FOR ; echo " done"
one
two done
$ printf "one\ntwo" | COMMAND_IM_LOOKING_FOR ; echo " done"
one
two done

(बाश और ज़श में कमांड प्रतिस्थापन सभी अनुगामी नई लाइनों को हटाता है, लेकिन मैं ऐसी चीज़ की तलाश कर रहा हूं जो एक अनुगामी नई लाइन को हटा देती है।)

जवाबों:


9

यह काम करना चाहिए:

printf "one\ntwo\n" | awk 'NR>1{print PREV} {PREV=$0} END{printf("%s",$0)}' ; echo " done"

स्क्रिप्ट हमेशा वर्तमान के बजाय पिछली लाइन को प्रिंट करती है, और अंतिम पंक्ति को अलग तरह से व्यवहार किया जाता है।

यह और अधिक विस्तार से क्या करता है:

  1. NR>1{print PREV} पिछली पंक्ति को प्रिंट करें (पहली बार को छोड़कर)।
  2. {PREV=$0}PREVचर में वर्तमान लाइन स्टोर ।
  3. END{printf("%s",$0)} अंत में, अंतिम लाइन प्रिंटआउट लाइन ब्रेक को प्रिंट करें।

यह भी ध्यान दें कि यह अंत में अधिकांश एक खाली लाइन को हटा देगा (हटाने के लिए कोई समर्थन नहीं "one\ntwo\n\n\n")।


15

आप perlबिना उपयोग कर सकते हैं chomp:

$ printf "one\ntwo\n" | perl -0 -pe 's/\n\Z//'; echo " done"
one
two done

$ printf "one\ntwo" | perl -0 -pe 's/\n\Z//'; echo " done"
one
two done

लेकिन chompखुद का उपयोग क्यों न करें :

$ printf "one\ntwo\n" | perl -pe 'chomp if eof'; echo " done"

4

यदि आप एक सटीक समतुल्य चाहते हैं chomp, तो मेरे दिमाग में आने वाली पहली विधि लैटिन समाधान है जो पहले से ही पोस्ट किया गया है । मैं कुछ अन्य तरीकों को जोड़ूंगा जो लागू नहीं होते हैं chompलेकिन कुछ सामान्य कार्यों को लागू करते हैं जो chompअक्सर उपयोग किए जाते हैं।

जब आप किसी पाठ को चर में रखते हैं, तो अंत में सभी नए अंक छीन लिए जाते हैं। तो ये सभी कमांड एक ही सिंगल-लाइन आउटपुट का उत्पादन करते हैं:

echo "$(printf 'one\ntwo') done"
echo "$(printf 'one\ntwo\n') done"
echo "$(printf 'one\ntwo\n\n') done"
echo "$(printf 'one\ntwo\n\n\n\n\n\n\n\n\n\n') done"

यदि आप कुछ पाठ को फ़ाइल की अंतिम पंक्ति या कमांड के आउटपुट में जोड़ना चाहते हैं, sedतो सुविधाजनक हो सकता है। GNU sed और अधिकांश अन्य आधुनिक कार्यान्वयनों के साथ, यह तब भी काम करता है, जब इनपुट एक newline¹ में समाप्त नहीं होता है; हालाँकि, यह एक नई पंक्ति नहीं जोड़ेगा अगर कोई पहले से ही नहीं था।

sed '$ s/$/ done/'

¹ हालाँकि यह सभी sed कार्यान्वयन के साथ काम नहीं करता है: sed एक टेक्स्ट प्रोसेसिंग टूल है, और एक फाइल जो खाली नहीं है और एक newline वर्ण के साथ समाप्त नहीं होती है, वह टेक्स्ट फ़ाइल नहीं है।


यह बिल्कुल इसके समकक्ष नहीं है chomp, क्योंकि chompकेवल एक ही अनुगामी न्यूलाइन पर हटा दिया जाता है।
फ्लिमल

@Flimm हां, सबसे स्पष्ट सटीक समतुल्य chompआवक समाधान होगा जो कि लैटिनसुद ने पहले से ही पोस्ट किया है। लेकिन कई मामलों chompमें एक काम करने के लिए सिर्फ एक उपकरण है, और मैं कुछ सामान्य कार्यों को करने के तरीके प्रदान करता हूं। इसे स्पष्ट करने के लिए मुझे अपना उत्तर अपडेट करने दें।
गिलेस एसओ- बुराई को रोकना '

1

एक और perlदृष्टिकोण। यह एक पूरे इनपुट को मेमोरी में पढ़ता है, इसलिए यह बड़ी मात्रा में डेटा के लिए एक अच्छा विचार नहीं हो सकता है (cuonglm का या उस awkके लिए दृष्टिकोण का उपयोग करें ):

$ printf "one\ntwo\n" | perl -0777pe 's/\n$//'; echo " done"
one
two done

धन्यवाद, @ स्टीफनचेज़लस, तय। किसी कारण से, यह स्विच हमेशा मुझे भ्रमित करता है !
terdon

0

मैं इसे एक github रेपो से कहीं snagged, लेकिन नहीं मिल सकता है जहां

हटाना-पीछे चल रिक्त लाइनों-sed

#!/bin/bash
#
# Delete all trailing blank lines.
# From http://sed.sourceforge.net/sed1line.txt
#
# Version: 1.3.0
# Created: 2011-01-02
# Updated: 2015-01-25
# Contact: Joel Parker Henderson (joel@joelparkerhenderson.com)
# License: GPL
##
set -euf
sed -e :a -e '/^\n*$/{$d;N;ba' -e '}'

0

सार

नई लाइन के बिना प्रिंट लाइनें, केवल एक नई लाइन जोड़ें अगर प्रिंट करने के लिए एक और रेखा है।

$ printf 'one\ntwo\n' | 

     awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }';   echo " done"

one
two done

अन्य उपाय

यदि हम एक फ़ाइल के साथ काम कर रहे थे, तो हम केवल एक चरित्र को उससे अलग कर सकते हैं (यदि यह एक नई पंक्ति में समाप्त होता है):

removeTrailNewline () {[$ (टेल -c 1 "$ 1")]] || truncate -s-1 "$ 1"; }

यह एक तेज़ समाधान है क्योंकि इसे फ़ाइल से केवल एक वर्ण को पढ़ने की आवश्यकता है और फिर इसे truncateपूरी फ़ाइल को पढ़े बिना सीधे ( ) में हटा दें ।

हालांकि, स्टडिन (एक धारा) के डेटा के साथ काम करते समय डेटा को पढ़ा जाना चाहिए, यह सब। और, यह पढ़ते ही "भस्म" हो जाता है। कोई पीछे नहीं (ट्रंकट के साथ)। एक धारा के अंत का पता लगाने के लिए हमें धारा के अंत तक पढ़ना होगा। उस बिंदु पर, इनपुट स्ट्रीम पर वापस जाने का कोई तरीका नहीं है, डेटा पहले ही "भस्म" हो चुका है। इसका मतलब है कि डेटा को बफर के कुछ रूप में संग्रहीत किया जाना चाहिए जब तक कि हम स्ट्रीम के अंत से मेल नहीं खाते हैं और फिर बफर में डेटा के साथ कुछ करते हैं।

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

परिवर्तनशील

भोले समाधान एक चर में पूरे इनपुट पर कब्जा करने के लिए किया जाएगा:

FilterOne(){ filecontents=$(cat; echo "x");        # capture the whole input
             filecontents=${filecontents%x};       # Remove the "x" added above.
             nl=$'\n';                             # use a variable for newline.
             printf '%s' "${filecontents%"$nl"}";  # Remove newline (if it exists).
       }

printf 'one\ntwo'     | FilterOne ; echo 1done
printf 'one\ntwo\n'   | FilterOne ; echo 2done
printf 'one\ntwo\n\n' | FilterOne ; echo 3done

याद

मेमोरी में एक पूरी फाइल को सेड के साथ लोड करना संभव है। Sed में अंतिम पंक्ति पर अनुगामी newline से बचना असंभव है। GNU सेड एक अनुगामी न्यूलाइन को प्रिंट करने से बच सकता है, लेकिन केवल अगर स्रोत फ़ाइल पहले से ही गायब है। तो, नहीं, सरल sed मदद नहीं कर सकता।

-zविकल्प के साथ GNU awk को छोड़कर :

sed -z 's/\(.*\)\n$/\1/'

Awk (किसी भी awk) के साथ, पूरी स्ट्रीम को खिसकाएं, और printfयह अनुगामी न्यूलाइन के बिना।

awk '    { content = content $0 RS } 
     END { gsub( "\n$", "", content ); printf( "%s", content ) }
    '

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

स्मृति में दो लाइनें

Awk में, हम पिछली लाइन को एक वेरिएबल में स्टोर करके और वर्तमान में प्रिन्ट करके दो लूप प्रति लूप प्रोसेस कर सकते हैं:

awk 'NR>1{print previous} {previous=$0} END {printf("%s",$0)}'

प्रत्यक्ष प्रसंस्करण

लेकिन हम बेहतर कर सकते थे।

अगर हम बिना लाइन के वर्तमान लाइन को प्रिंट करते हैं और अगली लाइन के मौजूद होने पर ही एक नई लाइन प्रिंट करते हैं, तो हम एक बार में एक लाइन को प्रोसेस करते हैं और आखिरी लाइन में एक ट्रेलिंग न्यूलाइन नहीं होगी :

awk 'NR == 1 {प्रिंटफ ("% s", $ 0); अगला}; {प्रिंटफ ("\ n% s", $ 0)} '

या, किसी और तरीके से लिखा गया है:

awk 'NR>1{ print "" }; { printf( "%s", $0 ) }'

या:

awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'

इसलिए:

$ printf 'one\ntwo\n' | awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'; echo " done"
one
two done
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.