फ़ाइल के अंत में एक नई पंक्ति कैसे जोड़ें?


190

संस्करण नियंत्रण प्रणालियों का उपयोग करके मैं शोर पर गुस्सा हो जाता हूं जब अंतर कहता है No newline at end of file

इसलिए मैं सोच रहा था: उन संदेशों से छुटकारा पाने के लिए फ़ाइल के अंत में एक नई पंक्ति कैसे जोड़ूं?



1
नीचे अच्छा समाधान है कि सभी फ़ाइलों को पुनरावर्ती रूप से साफ करता है। उत्तर @Patrick Oscity
Qwerty


आगे बढ़ते हुए, पाठ संपादकों के पास अक्सर यह सुनिश्चित करने के लिए विकल्प होते हैं कि एक नई अनुगामी हो, जिसे आप और आपके सहयोगी साफ रखने के लिए उपयोग कर सकें।
निक टी

जवाबों:


44

किसी प्रोजेक्ट को पुन: उपयोग करने के लिए मैं इस ऑनलाइनर का उपयोग करता हूं:

git ls-files -z | while IFS= read -rd '' f; do tail -c1 < "$f" | read -r _ || echo >> "$f"; done

स्पष्टीकरण:

  • git ls-files -zरिपॉजिटरी में फाइलों को सूचीबद्ध करता है। यह अतिरिक्त पैरामीटर के रूप में एक वैकल्पिक पैटर्न लेता है जो कुछ मामलों में उपयोगी हो सकता है यदि आप ऑपरेशन को कुछ फ़ाइलों / निर्देशिकाओं तक सीमित करना चाहते हैं। एक विकल्प के रूप में, आप find -print0 ...प्रभावित फ़ाइलों को सूचीबद्ध करने के लिए या इसी तरह के कार्यक्रमों का उपयोग कर सकते हैं - बस यह सुनिश्चित करें कि यह NULप्रविष्टियों को हटाता है।

  • while IFS= read -rd '' f; do ... done प्रविष्टियों के माध्यम से iterates, सुरक्षित रूप से फाइलनाम को संभालना जिसमें व्हॉट्सएप और / या नईलाइन शामिल हैं।

  • tail -c1 < "$f" एक फ़ाइल से अंतिम चार्ट पढ़ता है।

  • read -r _ यदि कोई अनुगामी न्यूलाइन अनुपलब्ध है, तो गैर-एक्सो निकास स्थिति के साथ बाहर निकलता है।

  • || echo >> "$f" यदि पिछली कमांड का एग्जिट स्टेटस नॉनजरो था तो फाइल को एक नई लाइन देता है।


आप इसे इस तरह से भी कर सकते हैं यदि आप अपनी फाइलों के सबसेट को सैनिटाइज करना चाहते हैं:find -name \*.java | while read f; do tail -n1 $f | read -r _ || echo >> $f; done
प्रति लुंडबर्ग

@ स्टीफनचेज़ेलस अच्छे सुझाव, इसे मेरे उत्तर में शामिल करने की कोशिश करेंगे।
पैट्रिक ऑस्सिटी

@PerLundberg आप एक पैटर्न भी पास कर सकते हैं git ls-filesजो आपको अभी भी उन फ़ाइलों को संपादित करने से बचाएगा, जिन्हें संस्करण नियंत्रण में ट्रैक नहीं किया गया है।
पैट्रिक ऑस्सिटी

@ स्टेफ़ेनचेज़लस IFS= ने विभाजक को जोड़ने के लिए आसपास के व्हाट्सएप को संरक्षित करना अच्छा है। शून्य समाप्त प्रविष्टियाँ केवल तभी प्रासंगिक होती हैं, जब आपके पास उनके नाम की एक नई पंक्ति के साथ फाइल या निर्देशिका होती है, जो एक तरह से दूर की कौड़ी लगती है, लेकिन जेनेरिक मामले को संभालने के लिए अधिक सही तरीका है, मैं सहमत हूं। बस एक छोटे से चेतावनी के रूप में: POSIX sh में -dविकल्प readउपलब्ध नहीं है।
पैट्रिक ऑस्सिटी

हां, इसलिए मेरे zsh / bash कीtail -n1 < "$f"फ़ाइल नाम से शुरू होने वाली समस्याओं से बचने के लिए मेरा उपयोग भी देखें -( जो फ़ाइल नाम के tail -n1 -- "$f"लिए काम नहीं करता है -)। आप स्पष्ट करना चाह सकते हैं कि उत्तर अब zsh / bash विशिष्ट है।
स्टीफन चेज़लस

202

यहाँ तुम जाओ :

sed -i -e '$a\' file

और वैकल्पिक रूप से OS X के लिए sed:

sed -i '' -e '$a\' file

यह \nफ़ाइल के अंत में तभी जुड़ता है जब यह पहले से ही एक नई पंक्ति के साथ समाप्त नहीं होता है। इसलिए यदि आप इसे दो बार चलाते हैं, तो यह एक और नई पंक्ति नहीं जोड़ेगा:

$ cd "$(mktemp -d)"
$ printf foo > test.txt
$ sed -e '$a\' test.txt > test-with-eol.txt
$ diff test*
1c1
< foo
\ No newline at end of file
---
> foo
$ echo $?
1
$ sed -e '$a\' test-with-eol.txt > test-still-with-one-eol.txt
$ diff test-with-eol.txt test-still-with-one-eol.txt
$ echo $?
0

1
@jwd: से man sed: $ Match the last line.लेकिन शायद यह केवल दुर्घटना से काम करता है। आपका समाधान भी काम करता है।
l0b0

1
आपका समाधान भी अधिक सुरुचिपूर्ण है, और मैंने इसे परीक्षण और प्रतिबद्ध किया है, लेकिन यह कैसे काम कर सकता है? यदि $अंतिम पंक्ति से मेल खाता है, तो यह स्ट्रिंग में एक और नई पंक्ति क्यों नहीं जोड़ता है जिसमें पहले से ही एक नई पंक्ति है ?
l0b0

27
के दो अलग-अलग अर्थ हैं $। एक रेगेक्स के अंदर, जैसे कि फॉर्म के साथ /<regex>/, इसका सामान्य "लाइन का मैच अंत" अर्थ है। अन्यथा, एक पते के रूप में उपयोग किया जाता है, sed इसे विशेष "फाइल में अंतिम पंक्ति" अर्थ देता है। कोड काम करता है क्योंकि डिफ़ॉल्ट रूप से sed अपने आउटपुट के लिए एक नईलाइन भेजता है अगर यह पहले से ही नहीं है। कोड "$ a \" बस कहता है "फ़ाइल की अंतिम पंक्ति से मेल खाता है, और इसमें कुछ भी नहीं जोड़ें।" लेकिन संक्षेप में, $अगर यह पहले से ही वहाँ नहीं है , तो sed हर पंक्ति में नई पंक्ति जोड़ता है (जैसे कि यह पंक्ति)।
19

1
मैनपेज के बारे में: आप जिस उद्धरण का उल्लेख कर रहे हैं, वह "पते" अनुभाग के अंतर्गत है। इसे अंदर रखना /regex/एक अलग अर्थ देता है। फ्रीबीएसडी मैनपेज
jwd

2
यदि फ़ाइल पहले से ही एक नई पंक्ति में समाप्त हो जाती है, तो यह इसे परिवर्तित नहीं करता है, लेकिन यह इसे फिर से लिखता है और इसकी टाइमस्टैम्प को अपडेट करता है। वह बात हो भी सकती है और नहीं भी।
कीथ थॉम्पसन

39

एक नज़र देख लो:

$ echo -n foo > foo 
$ cat foo
foo$
$ echo "" >> foo
$ cat foo
foo

तो echo "" >> noeol-fileचाल चलनी चाहिए। (या आप इन फ़ाइलों की पहचान करने और उन्हें ठीक करने के लिए पूछने का मतलब था ?)

संपादित हटाया ""से echo "" >> foo(@ yuyichao की टिप्पणी देखें) EDIT2 जोड़ा ""फिर से ( लेकिन @Keith थॉम्पसन के टिप्पणी देखें)


4
""आवश्यक (कम से कम पार्टी के लिए) नहीं है और tail -1 | wc -lअंत में एक नई लाइन के बिना फ़ाइल पता लगाने के लिए इस्तेमाल किया जा सकता
yuyichao

5
@ युयिचैओ: ""बैश के लिए आवश्यक नहीं है, लेकिन मैंने ऐसे echoकार्यान्वयन देखे हैं जो बिना किसी तर्क के लागू किए जाने पर कुछ भी नहीं छापते हैं (हालांकि उनमें से कोई भी जो अब मुझे मिल सकता है)। echo "" >> noeol-fileशायद थोड़ा और मजबूत है। printf "\n" >> noeol-fileऔर भी बहुत कुछ है।
कीथ थॉम्पसन

2
@KeithThompson, cshके echoउत्पादन में कुछ भी नहीं करने के लिए जाना जाता है जब किसी भी तर्क पारित नहीं किया है। लेकिन फिर अगर हम गैर बॉर्न की तरह गोले का समर्थन करने के लिए जा रहे हैं, हम इसे बनाना चाहिए echo ''बजाय echo ""के रूप में echo ""ouput हैं ""<newline>के साथ rcया esउदाहरण के लिए।
स्टीफन चेज़लस

1
@ स्टीफनचेज़ेलैस: और tcsh, इसके विपरीत csh, एक नई रेखा को प्रिंट करता है, जब बिना किसी तर्क के लागू किया जाता है - सेटिंग की परवाह किए बिना $echo_style
कीथ थॉम्पसन

16

एक और उपाय का उपयोग कर ed। यह समाधान केवल अंतिम पंक्ति को प्रभावित करता है और केवल तभी \nगायब होता है:

ed -s file <<< w

यह अनिवार्य रूप से एक स्क्रिप्ट के माध्यम से संपादन के लिए फ़ाइल खोलने का काम करता है, स्क्रिप्ट एकल wकमांड है, जो फ़ाइल को डिस्क पर वापस लिखती है। यह ed(1)मैन पेज में पाए गए इस वाक्य पर आधारित है :

सीमाएँ
       (...)

       यदि एक पाठ (गैर-बाइनरी) फ़ाइल को एक नई वर्ण द्वारा समाप्त नहीं किया जाता है,
       तब एड इसे पढ़ने / लिखने पर एक जोड़ देता है। एक बाइनरी के मामले में
       फ़ाइल, एड पढ़ने / लिखने पर एक नई रूपरेखा नहीं जोड़ते हैं।

1
यह मेरे लिए एक नई पंक्ति नहीं जोड़ता है।
ओल्होव्स्की

4
मेरे लिये कार्य करता है; यहां तक ​​कि यह "न्यूलाइन संलग्न" (आर्क लिनक्स पर एड-1.10-1) प्रिंट करता है।
स्टीफन माज्यूस्की

12

पाठ फ़ाइल में अनुपस्थित, अंतिम नई पंक्ति को जोड़ने के लिए एक सरल, पोर्टेबल, POSIX- संगत तरीका होगा:

[ -n "$(tail -c1 file)" ] && echo >> file

इस दृष्टिकोण को संपूर्ण फ़ाइल को पढ़ने की आवश्यकता नहीं है; यह बस ईओएफ की तलाश कर सकता है और वहां से काम कर सकता है।

इस दृष्टिकोण को आपकी पीठ के पीछे अस्थायी फाइलें बनाने की भी आवश्यकता नहीं है (जैसे sed -i), इसलिए हार्डलिंक प्रभावित नहीं होते हैं।

इको फ़ाइल के लिए केवल एक नई लाइन को जोड़ता है जब कमांड प्रतिस्थापन का परिणाम एक गैर-रिक्त स्ट्रिंग है। ध्यान दें कि यह तभी हो सकता है जब फ़ाइल खाली न हो और अंतिम बाइट कोई नई रेखा न हो।

यदि फ़ाइल का अंतिम बाइट एक नई रेखा है, तो पूंछ इसे वापस करती है, फिर कमांड प्रतिस्थापन इसे स्ट्रिप्स करता है; परिणाम एक रिक्त स्ट्रिंग है। एक परीक्षण विफल रहता है और प्रतिध्वनि नहीं चलती है।

यदि फ़ाइल खाली है, तो कमांड प्रतिस्थापन का परिणाम भी एक रिक्त स्ट्रिंग है, और फिर से प्रतिध्वनि नहीं चलती है। यह वांछनीय है, क्योंकि एक खाली फ़ाइल एक अमान्य पाठ फ़ाइल नहीं है, न ही यह एक खाली लाइन के साथ गैर-खाली पाठ फ़ाइल के बराबर है।


1
ध्यान दें कि यह काम नहीं करता है yashयदि फ़ाइल का अंतिम चरित्र मल्टी-बाइट चरित्र है (उदाहरण के लिए UTF-8 स्थानों में), या यदि लोकेल C है और फ़ाइल में अंतिम बाइट का 8 वां बिट सेट है। अन्य गोले (zsh को छोड़कर), यदि NUL बाइट में फ़ाइल समाप्त हो जाती है, तो यह एक नई पंक्ति नहीं जोड़ेगी (लेकिन फिर से, इसका मतलब है कि इनपुट एक नई पंक्ति में जुड़ने के बाद भी गैर-पाठ होगा)।
स्टीफन चेजलस


1
क्या फ़ोल्डर और सबफ़ोल्डर्स में हर फ़ाइल के लिए इसे चलाना संभव है?
क्वर्टी

12

परवाह किए बिना नई पंक्ति जोड़ें:

echo >> filename

यहां यह जांचने का एक तरीका है कि पायथन का उपयोग करके किसी एक को जोड़ने से पहले कोई नई पंक्ति अंत में मौजूद है या नहीं:

f=filename; python -c "import sys; sys.exit(open(\"$f\").read().endswith('\n'))" && echo >> $f

1
मैं किसी भी प्रकार के लूप में अजगर संस्करण का उपयोग नहीं करूंगा क्योंकि धीमी अजगर स्टार्टअप समय। यदि आप चाहते थे तो निश्चित रूप से आप अजगर में लूप कर सकते हैं।
केविन कॉक्स

2
अजगर के लिए स्टार्टअप का समय यहां 0.03 सेकंड है। क्या आप वास्तव में समस्याग्रस्त होने पर विचार करते हैं?
अलेक्जेंडर

3
स्टार्टअप टाइम मायने रखता है अगर आप एक लूप में अजगर को बुलाते हैं, यही कारण है कि मैंने कहा कि अजगर में लूप को करने पर विचार करें । तो फिर आप केवल एक बार स्टार्टअप लागत खर्च करते हैं। मेरे लिए, आधी लागत पूरे स्निपिट के आधे से अधिक स्टार्टअप की है, मैं उस पर्याप्त ओवरहेड पर विचार करूंगा। (फिर, अप्रासंगिक यदि केवल फाइलों की एक छोटी संख्या कर रही है)
केविन कॉक्स

2
echo ""से ज्यादा मजबूत लगता है echo -n '\n'। या आप उपयोग कर सकते हैंprintf '\n'
कीथ थॉम्पसन

2
यह मेरे लिए ठीक काम किया
डैनियल गोमेज़ रिको

8

सबसे तेज़ समाधान है:

[ -n "$(tail -c1 file)" ] && printf '\n' >>file 

  1. वास्तव में तेज है।
    एक मध्यम आकार की फ़ाइल पर seq 99999999 >fileयह मिलिसकॉन्ड लेता है।
    अन्य समाधानों में लंबा समय लगता है:

    [ -n "$(tail -c1 file)" ] && printf '\n' >>file  0.013 sec
    vi -ecwq file                                    2.544 sec
    paste file 1<> file                             31.943 sec
    ed -s file <<< w                             1m  4.422 sec
    sed -i -e '$a\' file                         3m 20.931 sec
  2. राख, बाश, लक्स, मक्ष, क्षश, अष्टम और जश में काम करता है लेकिन यश नहीं।

  3. यदि कोई नई पंक्ति जोड़ने की आवश्यकता नहीं है, तो फ़ाइल टाइमस्टैम्प को न बदलें।
    यहां प्रस्तुत अन्य सभी समाधान फ़ाइल के टाइमस्टैम्प को बदलते हैं।
  4. उपरोक्त सभी समाधान वैध POSIX हैं।

यदि आपको यश (और ऊपर सूचीबद्ध अन्य सभी गोले) के लिए एक समाधान पोर्टेबल की आवश्यकता है, तो यह थोड़ा और अधिक जटिल हो सकता है:

f=file
if       [ "$(tail -c1 "$f"; echo x)" != "$(printf '\nx')" ]
then     printf '\n' >>"$f"
fi

7

परीक्षण का सबसे तेज़ तरीका अगर किसी फ़ाइल की अंतिम बाइट एक नई रेखा है, तो केवल उस अंतिम बाइट को पढ़ना है। इसके साथ किया जा सकता है tail -c1 file। हालाँकि, यदि बाइट मान एक नई लाइन है, तो परीक्षण के लिए सरल तरीका, शेल विस्तार के आधार पर एक कमांड एक्सटेंशन के अंदर एक नई अनुगामी नई लाइन को हटाने में विफल रहता है (उदाहरण के लिए) यश में, जब फ़ाइल का अंतिम वर्ण UTF- होता है 8 मूल्य।

सही, POSIX- आज्ञाकारी, सभी (उचित) गोले जिस तरह से खोजने के लिए कि किसी फ़ाइल की अंतिम बाइट एक नई लाइन है या तो xxd या hexdump का उपयोग करें:

tail -c1 file | xxd -u -p
tail -c1 file | hexdump -v -e '/1 "%02X"'

फिर, ऊपर के आउटपुट की तुलना 0Aकरना एक मजबूत परीक्षा प्रदान करेगा।
अन्यथा खाली फ़ाइल में नई लाइन जोड़ने से बचने के लिए यह उपयोगी है।
वह फ़ाइल 0A, जो निश्चित रूप से अंतिम वर्ण प्रदान करने में विफल रहेगी :

f=file
a=$(tail -c1 "$f" | hexdump -v -e '/1 "%02X"')
[ -s "$f" -a "$a" != "0A" ] && echo >> "$f"

छोटा एवं सुन्दर। इसमें बहुत कम समय लगता है क्योंकि यह अंतिम बाइट (ईओएफ की तलाश) को पढ़ता है। इससे कोई फर्क नहीं पड़ता कि फाइल बड़ी है। फिर जरूरत पड़ने पर केवल एक बाइट डालें।

कोई अस्थायी फ़ाइलों की जरूरत है और न ही इस्तेमाल किया। कोई भी हार्डलिंक प्रभावित नहीं होती है।

यदि यह परीक्षण दो बार चलाया जाता है, तो यह एक और नई पंक्ति नहीं जोड़ेगा।


1
@ मुझे लगता है कि यह उपयोगी जानकारी जोड़ता है।
सोरंटार

2
ध्यान दें कि न तो xxdहै और न ही hexdumpPOSIX उपयोगिताओं कर रहे हैं। POSIX टूलकिट में, od -An -tx1बाइट का हेक्स मान प्राप्त करना है।
स्टीफन चेज़लस

@ स्टीफनचेज़लस कृपया जवाब के रूप में पोस्ट करें; मैं यहाँ कई बार इस टिप्पणी की तलाश में आया हूँ :)
केल्विन


ध्यान दें कि POSIX LF के मान को 0x0a होने की गारंटी नहीं देता है। वहाँ अभी भी POSIX सिस्टम हैं जहां यह (EBCDIC आधारित) नहीं हैं, हालांकि वे इन दिनों बेहद दुर्लभ हैं।
स्टीफन चेजलस

4

आप अंतिम रूप से फाइल को संपादित करने वाले उपयोगकर्ता के संपादक को सुधारने से बेहतर हैं। यदि आप फ़ाइल को संपादित करने वाले अंतिम व्यक्ति हैं - आप किस संपादक का उपयोग कर रहे हैं, तो मैं टेक्स्टमेट का अनुमान लगा रहा हूं ..?


2
विम प्रश्न में संपादक हैं। लेकिन सामान्य तौर पर, आप सही कह रहे हैं, मुझे केवल
सीमा शुल्क को

6
विम के लिए, आपको अपने रास्ते से बाहर जाना होगा और फाइल के अंत में एक नई लाइन नहीं जोड़ने के लिए vim पाने के लिए बाइनरी-फाइल-ऑन-सेव डांस करना होगा - बस उस डांस को न करें। या, केवल मौजूदा फ़ाइलों को सही करने के लिए उन्हें vim में खोलें और फ़ाइल को सेव करें और vim आपके लिए लापता
नईलाइन

3
मेरी emacsफ़ाइल के अंत में एक नई पंक्ति नहीं है।
enzotib

2
टिप्पणी के लिए धन्यवाद @ AD7six, मैं जब मैं बातें करता हूं, तो इस बारे में प्रेत रिपोर्ट अलग-अलग मिलती रहती है कि मूल फ़ाइल में अंत में नई पंक्ति नहीं है। इससे कोई फर्क नहीं पड़ता कि कैसे मैं एक फ़ाइल को विम के साथ संपादित करता हूं, मैं इसे वहां एक नई पंक्ति नहीं डाल सकता। तो यह सिर्फ यह कर रही है।
स्टीवन लू

1
@enzotib: मेरे पास है (setq require-final-newline 'ask)मेरे में.emacs
कीथ थॉम्पसन

3

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

outputting_program | { cat ; echo ; }

यह भी POSIX शिकायत है।

फिर, ज़ाहिर है, आप इसे एक फ़ाइल पर पुनर्निर्देशित कर सकते हैं।


2
तथ्य यह है कि मैं इसे एक पाइपलाइन में उपयोग कर सकता हूं मददगार है। यह मुझे हेडर को छोड़कर एक सीएसवी फ़ाइल में पंक्तियों की संख्या गिनने की अनुमति देता है। और यह विंडोज़ फ़ाइलों पर एक सटीक लाइन काउंट प्राप्त करने में मदद करता है जो कि एक नई लाइन या कैरिज रिटर्न के साथ समाप्त नहीं होते हैं। cat file.csv | tr "\r" "\n" | { cat; echo; } | sed "/^[[:space:]]*$/d" | tail -n +2 | wc -l
काइल तोले

3

बशर्ते इनपुट में कोई नल न हों:

paste - <>infile >&0

... अगर यह पहले से ही एक नहीं था तो हमेशा एक नवजात शिशु के पूंछ के अंत तक एक नई रेखा को जोड़ना होगा। और इसे सही होने के लिए केवल एक बार इनपुट फ़ाइल को पढ़ने की आवश्यकता है।


यह उस तरह से काम नहीं करेगा जैसे स्टडिन और स्टडआउट एक ही ओपन-फाइल विवरण (फ़ाइल के भीतर कर्सर) साझा करते हैं। आपको paste infile 1<> infileइसके बजाय की आवश्यकता होगी ।
स्टीफन चेजलस

2

हालांकि यह सीधे सवाल का जवाब नहीं देता है, यहां एक संबंधित स्क्रिप्ट है जो मैंने उन फ़ाइलों का पता लगाने के लिए लिखी है जो नई पंक्ति में समाप्त नहीं होती हैं। यह बहुत तेज़ है।

find . -type f | # sort |        # sort file names if you like
/usr/bin/perl -lne '
   open FH, "<", $_ or do { print " error: $_"; next };
   $pos = sysseek FH, 0, 2;                     # seek to EOF
   if (!defined $pos)     { print " error: $_"; next }
   if ($pos == 0)         { print " empty: $_"; next }
   $pos = sysseek FH, -1, 1;                    # seek to last char
   if (!defined $pos)     { print " error: $_"; next }
   $cnt = sysread FH, $c, 1;
   if (!$cnt)             { print " error: $_"; next }
   if ($c eq "\n")        { print "   EOL: $_"; next }
   else                   { print "no EOL: $_"; next }
'

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

नोट: स्क्रिप्ट उन फ़ाइल नामों को संभालती नहीं है जिनमें नई सूचियाँ हैं। यदि आप एक GNU या BSD सिस्टम पर हैं, तो आप -0 को खोजने के लिए, -z को सॉर्ट करने के लिए, और -0 से perl, जैसे सभी संभावित फ़ाइल नाम को संभाल सकते हैं:

find . -type f -print0 | sort -z |
/usr/bin/perl -ln0e '
   open FH, "<", $_ or do { print " error: $_"; next };
   $pos = sysseek FH, 0, 2;                     # seek to EOF
   if (!defined $pos)     { print " error: $_"; next }
   if ($pos == 0)         { print " empty: $_"; next }
   $pos = sysseek FH, -1, 1;                    # seek to last char
   if (!defined $pos)     { print " error: $_"; next }
   $cnt = sysread FH, $c, 1;
   if (!$cnt)             { print " error: $_"; next }
   if ($c eq "\n")        { print "   EOL: $_"; next }
   else                   { print "no EOL: $_"; next }
'

बेशक, आपको अभी भी आउटपुट में newlines के साथ फ़ाइल नामों को एन्कोडिंग के तरीके के साथ आना होगा (पाठक के लिए एक अभ्यास के रूप में छोड़ दिया गया)।

आउटपुट को फ़िल्टर्ड किया जा सकता है, यदि वांछित है, तो उन फ़ाइलों को एक नईलाइन संलग्न करने के लिए जिनके पास एक नहीं है, सबसे सरल रूप से

 echo >> "$filename"

अंतिम न्यूलाइन का अभाव स्क्रिप्ट में बग पैदा कर सकता है क्योंकि शेल और अन्य उपयोगिताओं के कुछ संस्करण ठीक से एक लापता फाइनल न्यूलाइन को संभाल नहीं पाएंगे, जब इस तरह की फाइल पढ़ रहे हों।

मेरे अनुभव में, फ़ाइलों को संपादित करने के लिए विभिन्न विंडोज उपयोगिताओं का उपयोग करके एक अंतिम न्यूलाइन की कमी है। मैंने कभी भी किसी फाइल को संपादित करते समय एक लापता अंतिम न्यूलाइन को देखा नहीं है, हालांकि यह ऐसी फाइलों पर रिपोर्ट करेगा।

अंत में, बहुत कम (लेकिन धीमे) स्क्रिप्ट हैं जो उन फ़ाइलों को प्रिंट करने के लिए उनके फ़ाइल नाम इनपुट पर लूप कर सकते हैं, जो नईलाइन में समाप्त नहीं होते हैं, जैसे:

/usr/bin/perl -ne 'print "$ARGV\n" if /.\z/' -- FILE1 FILE2 ...

1

vi/ vim/ exसंपादकों स्वचालित रूप से जोड़ <EOL>EOF पर जब तक फ़ाइल पहले से ही यह है।

तो या तो प्रयास करें:

vi -ecwq foo.txt

जो इसके बराबर है:

ex -cwq foo.txt

परिक्षण:

$ printf foo > foo.txt && wc foo.txt
0 1 3 foo.txt
$ ex -scwq foo.txt && wc foo.txt
1 1 4 foo.txt

कई फ़ाइलों को ठीक करने के लिए , जाँच करें: बहुत सारी फ़ाइलों के लिए 'फ़ाइल के अंत में कोई नई पंक्ति' कैसे तय करें? एसओ पर

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


0

वर्तमान निर्देशिका (प्लस उपनिर्देशिका) में सभी फाइलों के स्वीकृत उत्तर को लागू करने के लिए:

$ find . -type f -exec sed -i -e '$a\' {} \;

यह लिनक्स (उबंटू) पर काम करता है। ओएस एक्स पर आपको संभवतः -i ''(अप्रयुक्त) का उपयोग करना होगा ।


4
ध्यान दें कि find .सभी फाइलों को सूचीबद्ध करता है, जिसमें फाइलें भी शामिल हैं .git। बाहर करने के लिए:find . -type f -not -path './.git/*' -exec sed -i -e '$a\' {} \;
तले हुए पानी की बोतल

काश मैंने यह टिप्पणी पढ़ी होती / इसके बारे में सोचा होता इससे पहले कि मैं इसे चलाता। ओह अच्छा।
kstev

0

जीएनयू संस्करणों में कम से कम, बस grep ''याawk 1 अपने इनपुट canonicalizes, एक अंतिम न्यू लाइन यदि पहले से ही मौजूद नहीं जोड़ रहा है। वे प्रक्रिया में फ़ाइल की प्रतिलिपि बनाते हैं, जिसमें समय लगता है अगर बड़े (लेकिन स्रोत को किसी भी तरह से पढ़ने के लिए बहुत बड़ा नहीं होना चाहिए?) और मॉडरेट को अपडेट करता है जब तक कि आप कुछ ऐसा नहीं करते हैं

 mv file old; grep '' <old >file; touch -r old file

(हालांकि यह एक फ़ाइल पर ठीक हो सकता है जिसे आप चेक-इन कर रहे हैं क्योंकि आपने इसे संशोधित किया है) और यह हार्डलिंक्स, नॉन्डफॉल्ट अनुमतियों और एसीएल आदि को खो देता है जब तक कि आप और भी सावधान न हों।


या बस grep '' file 1<> file, हालांकि वह अभी भी पूरी तरह से फ़ाइल को पढ़ेगा और लिखेगा।
स्टीफन चेज़लस

-1

यह AIX ksh में काम करता है:

lastchar=`tail -c 1 *filename*`
if [ `echo "$lastchar" | wc -c` -gt "1" ]
then
    echo "/n" >> *filename*
fi

मेरे मामले में, यदि फ़ाइल नईलाइन याद कर रही है, तो wcकमांड का मान वापस आ जाता है 2और हम एक नई पंक्ति लिखते हैं।


प्रतिक्रिया अप या डाउनवोट्स के रूपों में आएगी, या आपको टिप्पणियों में आपके उत्तरों / प्रश्नों को अधिक रेखांकित करने के लिए कहा जाएगा, उत्तर के निकाय में इसके लिए पूछने का कोई मतलब नहीं है। इसे बिंदु पर रखें, स्टेक्सएक्सचेंज में आपका स्वागत है!
k0pernikus

-1

पैट्रिक ऑस्सिटी के उत्तर में जोड़ना , यदि आप इसे किसी विशिष्ट निर्देशिका में लागू करना चाहते हैं, तो आप भी उपयोग कर सकते हैं:

find -type f | while read f; do tail -n1 $f | read -r _ || echo >> $f; done

इसे उस डायरेक्टरी के अंदर चलाएं, जिसमें आप नए लिंक जोड़ना चाहते हैं।


-1

echo $'' >> <FILE_NAME> फ़ाइल के अंत में एक रिक्त रेखा जोड़ देगा।

echo $'\n\n' >> <FILE_NAME> फ़ाइल के अंत में 3 रिक्त लाइनें जोड़ देगा।


StackExchange का एक अजीब प्रारूप है, मैंने इसे आपके लिए तय किया है :-)
peterh

-1

यदि आपकी फाइल विंडोज लाइन एंडिंग के साथ समाप्त हो गई है \r\nऔर आप लिनक्स में हैं तो आप इस sedकमांड का उपयोग कर सकते हैं । यह केवल \r\nअंतिम पंक्ति में जोड़ता है यदि यह पहले से ही नहीं है:

sed -i -e '$s/\([^\r]\)$/\1\r\n/'

स्पष्टीकरण:

-i    replace in place
-e    script to run
$     matches last line of a file
s     substitute
\([^\r]\)$    search the last character in the line which is not a \r
\1\r\n    replace it with itself and add \r\n

यदि अंतिम पंक्ति में पहले से ही एक समाहित है, \r\nतो खोज रेगेक्सप मेल नहीं खाएगा, इसलिए कुछ भी नहीं होगा।


-1

आप एक fix-non-delimited-lineस्क्रिप्ट लिख सकते हैं जैसे:

#! /bin/zsh -
zmodload zsh/system || exit
ret=0
for file do
  if sysopen -rwu0 -- "$file"; then
    if sysseek -w end -1; then
      read -r x || print -u0
    else
      syserror -p "Can't seek in $file before the last byte: "
      ret=1
    fi
  else
    ret=1
  fi
done
exit $ret

यहां दिए गए कुछ समाधानों के विपरीत, यह

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

आप इसे उदाहरण के लिए उपयोग कर सकते हैं:

that-script *.txt

या:

git ls-files -z | xargs -0 that-script

POSIXly, आप कुछ कार्यात्मक समकक्ष के साथ कर सकता है

export LC_ALL=C
ret=0
for file do
  [ -s "$file" ] || continue
  {
    c=$(tail -c 1 | od -An -vtc)
    case $c in
      (*'\n'*) ;;
      (*[![:space:]]*) printf '\n' >&0 || ret=$?;;
      (*) ret=1;; # tail likely failed
    esac
  } 0<> "$file" || ret=$? # record failure to open
done
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.