क्या vi चुपचाप फ़ाइल के अंत में एक नई पंक्ति (LF) जोड़ देता है?


36

मुझे एक अजीब व्यवहार को समझने में परेशानी होती है: vi फ़ाइल की समाप्ति पर एक नई पंक्ति (ASCII: LF, जोड़ते हैं क्योंकि यह एक यूनिक्स ( AIX ) प्रणाली है, जब मैंने विशेष रूप से इसे टाइप नहीं किया था।

मैं फ़ाइल को vi में संपादित करता हूं (इस बात का ध्यान रखता हूं कि अंत में कोई नई इनपुट न डालें):

# vi foo   ## Which I will finish on the char "9" and not input a last newline, then `:wq`
123456789
123456789
123456789
123456789
~
~
  ## When I save, the cursor is just above the last "9", and no newline was added.

मुझे उम्मीद है कि वीआई इसे "जैसा है", वैसे ही 39 बाइट्स होने की उम्मीद है: पहली तीन पंक्तियों में से प्रत्येक पर 10 ASCII वर्ण (संख्या 1 से 9, इसके बाद एक नई पंक्ति (मेरे सिस्टम पर LF)) और अंतिम पर केवल 9 लाइन (अक्षर 1 से 9, कोई समाप्ति वाली नई पंक्ति / LF) नहीं।

लेकिन ऐसा प्रतीत होता है जब मैं इसे सहेजता हूं तो यह 40 बाइट्स (39 के बजाय) है, और ओडी एक समाप्तिकारी एलएफ दिखाता है :

# wc foo
       4       4      40 foo  ## I expected 39 here! as I didn't add the last newline
# od -a toto
0000000    1   2   3   4   5   6   7   8   9  lf   1   2   3   4   5   6
0000020    7   8   9  lf   1   2   3   4   5   6   7   8   9  lf   1   2
0000040    3   4   5   6   7   8   9  lf
0000050
     ## An "lf" terminates the file?? Did vi add it silently?

अगर मैं एक प्रिंटफ के साथ फाइल बनाता हूं, जो मैंने vi के अंदर किया है, तो यह उम्मीद के मुताबिक काम करता है:

# ## I create a file with NO newline at the end:
# printf "123456789\n123456789\n123456789\n123456789" > foo2
# wc foo2  ## This one is as expected: 39 bytes, exactly as I was trying to do above with vi.
       3       4      39 foo  ## As expected, as I didn't add the last newline

  ## Note that for wc, there are only three lines!
  ## (So wc -l doesn't count lines; it counts the [newline] chars... Which is rather odd.)

# root@SPU0WMY1:~  ## od -a foo2
0000000    1   2   3   4   5   6   7   8   9  lf   1   2   3   4   5   6
0000020    7   8   9  lf   1   2   3   4   5   6   7   8   9  lf   1   2
0000040    3   4   5   6   7   8   9
0000047                                ## As expected, no added LF.

दोनों फ़ाइलें (foo (40 अक्षर) और foo2 (39 अक्षर) बिल्कुल एक जैसी दिखाई देती हैं अगर मैं उन्हें vi के साथ फिर से खोलूं ...

और अगर मैं vi में foo2 (39 अक्षर, कोई समाप्त करने वाली नई पंक्ति) नहीं खोलता हूं और इसे संपादित किए बिना करता हूं:wq , तो यह कहता है कि यह 40 वर्ण लिखता है, और लाइनफीड दिखाई देता है!

मेरे पास हाल ही के vi (IIX, vi (not Vim ) संस्करण 3.10 मैं ऐसा सोचता हूं पर ऐसा नहीं कर सकता हूं। मैं (कोई "-वर्जन" या इसे जानने के अन्य साधन नहीं)।

# strings /usr/bin/vi | grep -i 'version.*[0-9]'
@(#) Version 3.10

क्या यह vi के लिए सामान्य है (और शायद अधिक हाल के संस्करण में नहीं? या विम?) चुपचाप एक फ़ाइल के अंत में एक नई पंक्ति जोड़ने के लिए? (मुझे लगता है कि ~ ने संकेत दिया कि पिछली पंक्ति एक नई रेखा के साथ समाप्त नहीं हुई थी।)

-

संपादित करें: कुछ अतिरिक्त अपडेट और सारांश, नीचे दिए गए उत्तर के लिए एक बड़े धन्यवाद के साथ:

  • vi चुपचाप उस समय एक अनुगामी नई पंक्ति जोड़ते हैं, जिसमें एक फ़ाइल होती है जिसमें इसकी कमी होती है (जब तक कि फ़ाइल खाली न हो)।

  • यह केवल लेखन समय पर ऐसा करता है! (यानी, जब तक आप: डब्ल्यू, आप उपयोग कर सकते हैं: ई यह सत्यापित करने के लिए कि फ़ाइल अभी भी है जैसा कि आपने इसे खोला है ... (यानी: यह अभी भी "फ़ाइल नाम" दिखाता है [अंतिम पंक्ति पूरी नहीं है] एन लाइन, एम चरित्र)। जब आप सहेजते हैं, तो एक नई चेतावनी चुपचाप जोड़ी जाती है, एक विशिष्ट चेतावनी के बिना (यह कहता है कि यह कितने बाइट्स बचाता है, लेकिन यह ज्यादातर मामलों में एक नई रेखा को जोड़ने के लिए पर्याप्त नहीं है) (मेरे बारे में बात करने के लिए @jiliagre के लिए धन्यवाद) vi संदेश को खोलने से, मुझे यह जानने में मदद मिली कि परिवर्तन वास्तव में कब होगा)

  • यह (मौन सुधार) POSIX व्यवहार है! (संदर्भों के लिए @ नंगे पांव देखें)


बस पूर्णता के लिए, AIX का कौन सा संस्करण (पूर्ण संस्करण)।
आठबेटटोनी

2
मैं इस विकल्प होने AIX के vi के बारे में पता नहीं कर रहा हूँ - प्रकट होता है केवल विम-
जेफ स्कालर

1
@JeffSchaller: लिंक के लिए thx। दुर्भाग्य से देशी vi में ": noeol सेट नहीं है" और न ही -b विकल्प भी है जो बाइनरी मोड में खुलता है ...
Olivier Dulac

1
आप कमांड viचलाकर इसके मूल के बारे में संस्करण या कम से कम एक सुराग प्राप्त करने में सक्षम हो सकते हैं :ve
जुलियागेरे

1
@ThomasDickey वास्तव में। किसी कारण से, आईबीएम ने exमैनुअल पेज को नीचे कर दिया, जहां :verकमांड को सामान्य रूप से प्रलेखित किया जाता है।
jlliagre

जवाबों:


28

यह अपेक्षित viव्यवहार है।

आपकी फ़ाइल में एक अधूरी अंतिम पंक्ति है इसलिए सख्ती से बोलना (यानी POSIX मानक के अनुसार), यह एक पाठ फ़ाइल नहीं है बल्कि एक बाइनरी फ़ाइल है।

vi जो एक पाठ फ़ाइल संपादक है, बाइनरी एक नहीं है, जब आप इसे बचाते हैं

यह अन्य पाठ फ़ाइल टूल जैसे wc, sedऔर अपेक्षित आउटपुट प्रदान करने के लिए पसंद करता है। ध्यान दें कि viसमस्या के बारे में चुप नहीं है:


$ printf "one\ntwo" >file     # Create a unterminated file
$ cat file                    # Note the missing newline before the prompt
one
two$ wc -l file               # wc ignores the incomplete last line
       1 file
$ sed '' file > file1
$ cat file1                   # so does a legacy sed
one
$ PATH=$(getconf PATH) sed  '' file
one                           # while a POSIX conformant sed warns you:
sed: Missing newline at end of file file.
two
$ vi file
one
two
~
~
~                             # vi tells you too about the issue
"file" [Incomplete last line] 2 lines, 7 characters

:w

"file" 2 lines, 8 characters  # and tells it writes two lines
                              # You'll even notice it writes one more
                              # character if you are a very shrewd observer :-)
:q
$ cat file                    # the file is now valid text
one
two
$ wc -l file                  # wc reports the expected number of lines
       2 file
$ sed '' file > file1         # sed works as expected
$ cat file1
one
two

ध्यान दें, viआप किस संस्करण के बारे में कुछ सुराग प्राप्त करने के लिए :veकमांड का उपयोग कर सकते हैं । यह दिखाता है कि मैं यहाँ एक विरासत SVR4 का उपयोग कर रहा हूँ, निश्चित रूप से नहीं vim:

:ve
Version SVR4.0, Solaris 2.5.0

जाहिर है, तुम्हारा कहना है:

:ve
Version 3.10

इसका मतलब है कि AIX viSVR3 स्रोत कोड पर आधारित है।

किसी भी स्थिति में, यह व्यवहार और [Incomplete last line]चेतावनी संदेश viकम से कम 1979 के बाद से विरासत बिल जोय के स्रोत कोड में है और AFAIK, सिस्टम V स्रोत कोड रिलीज़ से बनाई गई सभी शाखाओं में बनाए रखा गया है, जिसमें से AIX जैसे मालिकाना यूनिक्स बनाए गए थे।

कालानुक्रमिक रूप से कहें तो यह व्यवहार पोसक अनुरूपता का परिणाम नहीं है, बल्कि बिल जॉयस टेक्स्ट फाइलों को संपादित करने वाले उपयोगकर्ताओं के साथ बिल जॉय के मूल निर्णय के सहायक होने का एक परिणाम है, और फिर, एक दशक बाद, इस सहिष्णुता को बनाए रखने के लिए POSIX समिति का निर्णय।

यदि आप edइसके बजाय का उपयोग करते हैं vi, तो आप देखेंगे कि पूर्व मुद्दे के बारे में अधिक edक्रिया है , कम से कम यदि आपका SVR3 या नए कंप्यूटर शाखा से है:

$ ed file
'\n' appended
8
q

ध्यान दें कि एक खाली फ़ाइल एक मान्य पाठ फ़ाइल है जिसमें शून्य रेखाएँ होती हैं। जैसा कि तब ठीक करने के लिए कोई भी असंबद्ध पंक्ति viनहीं है, फ़ाइल को सहेजते समय एक नई रेखा नहीं जोड़ती है ।


1
मेरा मानना ​​है कि आप vi के लिए गलती करते हैं;) विरासत vi इस से बहुत कम क्रिया है ...
Olivier Dulac

@OlivierDulac मैं उन्हें भ्रमित नहीं कर रहा हूं। यह परीक्षण एसवीआर 4 विरासत का उपयोग करके किया गया था viजैसे ओपी करता है, हालांकि एक अलग यूनिक्स पर। यह vimया कोई अन्य क्लोन नहीं है। इसे स्पष्ट करने के लिए अद्यतन उत्तर दें।
जलेगीरे

@OlivierDulac हम्म, मैंने अभी देखा कि आप वास्तव में ओपी हैं। ऐसा लगता है कि AIX इसके viकार्यान्वयन के लिए एक पुराने सिस्टम V शाखा का उपयोग कर रहा है। संभवतः SVR3। क्या आप सुनिश्चित हैं कि [Incomplete last line]फ़ाइल खोलते समय कोई संदेश नहीं है ?
22

@OlivierDulac यह लिंक लगाने के लिए लगता है कि यह बहुत ही संदेश AIX viकार्यान्वयन द्वारा प्रदर्शित किया जा सकता है : www-01.ibm.com/support/docview.wss?uid=isg1IZ27694
jlliagre

मैं कल इसे देखने की कोशिश करूंगा
Olivier Dulac

51

POSIX को इस व्यवहार की आवश्यकता है, इसलिए यह किसी भी तरह से असामान्य नहीं है।

से POSIX मैनुअल vi :

INPUT फ़ाइलें

Vi कमांड द्वारा समर्थित इनपुट फ़ाइलों के विवरण के लिए पूर्व कमांड के INPUT FILES अनुभाग देखें।

POSIX पूर्व मैनुअल के निशान के बाद :

INPUT फ़ाइलें

इनपुट फाइलें पाठ फाइलें या फाइलें होंगी जो एक अधूरी अंतिम पंक्ति के अलावा पाठ फाइलें होंगी जो लंबाई में {LINE_MAX} -1 बाइट्स से अधिक लंबी नहीं होती हैं और इनमें NUL वर्ण नहीं होते हैं। डिफ़ॉल्ट रूप से, किसी भी अपूर्ण अंतिम पंक्ति को माना जाएगा जैसे कि उसके पास एक अनुवर्ती <newline> था। फ़ाइलों के अन्य रूपों का संपादन वैकल्पिक रूप से पूर्व कार्यान्वयन द्वारा अनुमति दी जा सकती है।

Vi मैनुअल के OUTPUT FILES अनुभाग को भी पूर्व में पुनर्निर्देशित किया गया है:

OUTPUT फ़ाइलें

पूर्व से आउटपुट पाठ फ़ाइलें होंगी।

POSIX परिभाषाओं की एक जोड़ी:

3.397 टेक्स्ट फाइल

एक फ़ाइल जिसमें वर्ण शून्य या अधिक लाइनों में व्यवस्थित होते हैं। लाइनों में NUL वर्ण नहीं हैं और कोई भी <newline> वर्ण सहित लंबाई में {LINE_MAX} बाइट्स से अधिक नहीं हो सकता है। हालांकि POSIX.1-2008 पाठ फ़ाइलों और बाइनरी फ़ाइलों (आईएसओ सी मानक देखें) के बीच अंतर नहीं करता है, कई उपयोगिताओं केवल पाठ फ़ाइलों पर काम करते समय अनुमानित या सार्थक आउटपुट उत्पन्न करती हैं। मानक उपयोगिताओं जिनके पास इस तरह के प्रतिबंध हैं, हमेशा अपने STDIN या INPUT FILES अनुभागों में "पाठ फ़ाइलों" को निर्दिष्ट करते हैं।

3.206 लाइन

शून्य या अधिक गैर- <newline> वर्णों के साथ-साथ एक समाप्ति <newline> वर्ण का क्रम।

इन मैनुअल पेज अंशों के संदर्भ में इन परिभाषाओं का मतलब है कि एक अनुरूप पूर्व / vi कार्यान्वयन को एक विकृत पाठ फ़ाइल को स्वीकार करना चाहिए, यदि उस फ़ाइल की केवल विकृति एक अनुपस्थित अंतिम नई रेखा है, जब उस फ़ाइल के बफर को लिखते समय परिणाम एक मान्य पाठ फ़ाइल होना चाहिए।

जबकि इस पोस्ट ने POSIX मानक के 2013 संस्करण को संदर्भित किया है, 1997 के पुराने संस्करण में भी प्रासंगिक वजीफे दिखाई देते हैं

अंत में, यदि आपको पूर्व की न्यूलाइन की अपील अनजानी लगती है, तो आप सातवें संस्करण UNIX's (1979) के असहिष्णु एड द्वारा गहराई से उल्लंघन महसूस करेंगे। मैनुअल से :

किसी फ़ाइल को पढ़ते समय, एडीसीआईआई एनयूएल पात्रों और सभी पात्रों को अंतिम नई पंक्ति के बाद संपादित करता है। यह गैर- ASCII वर्णों वाली फ़ाइलों को पढ़ने से इनकार करता है।


धन्यवाद, जो मेरे सवाल का जवाब देता है। मैं बस कुछ और दिनों के इंतजार में रहूँगा अगर कुछ बेहतर उत्तर उपनिवेश दें, लेकिन अभी मुझे लगता है कि आप स्वीकृत उत्तर हो सकते हैं।
ओलिवियर दुलक

बहुत अच्छी तरह से प्रलेखित उत्तर पर किया गया, सीधे चश्मे से! :)
वाइल्डकार्ड

1
@Wildcard, व्यवहार हालांकि चश्मा से पहले था।
जुलियाग्रे

@ जैलीग्रे, जब तक आपके पास बिल जॉय का एक संस्मरण या शायद ex(उनके नाम का पता नहीं है), मुझे लगता है कि POSIX चश्मा उतने ही अच्छे हैं जितनी उम्मीद की जा सकती है। ;) इस बिंदु से "मूल स्रोत" के सबसे करीब, हालांकि यह सच है कि वे मौजूदा कार्यक्षमता के अधिक या कम विवरण के रूप में शुरू हुए।
वाइल्डकार्ड

3
@Wildcard exबिल जॉय और चक एले ( web.cecs.pdx.edu/~kirkenda/joy84.html ) द्वारा लिखा गया था । मैं POSIX चश्मा पर सवाल नहीं उठाता और तथ्य यह है कि वर्तमान viरिलीज इसका पालन करते हैं, मैं सिर्फ व्यवहार बताता हूं । लंबे समय से यह भविष्यवाणी करता है।
jlliagre

1

मुझे कोई अन्य व्यवहार याद नहीं है कि एक फ़ाइल के अंत में एक नई रेखा जोड़ी जाती है ( vi80 के दशक के मध्य से)।

~इंगित करता है कि स्क्रीन है कि पाठ का हिस्सा नहीं है पर एक पंक्ति, नहीं है कि फाइल एक नई पंक्ति में खत्म नहीं होता। (यदि आप ~शेल स्क्रिप्ट की अंतिम पंक्ति पर रखते हैं, तो आपको त्रुटियों का पता लगाना मुश्किल हो सकता है )। यदि आप एक नई फ़ाइल के साथ एक छोटी फ़ाइल को अंत में लोड करते हैं, तो ~आप स्वयं देखेंगे और यह नापसंद करेंगे कि आपका विचार गैर-नई-पंक्ति वाले पाठ को इंगित करता है।


मुझे आश्चर्य है कि एक नई पंक्ति के अलावा क्या है ... मुझे उम्मीद है कि vi इसे चुपचाप नहीं जोड़ेंगे, लेकिन ऐसा लगता है कि यह करता है ... मैं इस रवैये की व्याख्या की तलाश कर रहा हूं (परेशान करने वाला तथ्य यह है: मैं foo2 खोलता हूं (बिना) LF के पीछे) और बस: wq, यह इसकी सामग्री को बदल देता है ... इसलिए यह मुझे कुछ दिखाता है लेकिन एक और चीज़ बचाता है ... अजीब, कम से कम कहने के लिए ^ ^
ओलिवियर दुलैक

इसके पूर्ववर्ती ( ed) में आप लाइनों को बनाएंगे और उन्हें संपादित करेंगे, न कि पात्रों को जोड़कर। मैंने हमेशा vi के बारे में एक पंक्ति उन्मुख संपादक के रूप में अच्छी तरह से सोचा। लेकिन मैं आपके आश्चर्य को समझता हूं।
एंथन

1

पाठ जिसमें अनुचित रूप से whileअंतिम लाईन के माध्यम से अंतिम न्यूलाइन रन का अभाव है, अंतिम पंक्ति में चुपचाप छोड़ दिया जाता है।

$ (echo transaction 1; echo -n transaction 2) \
  | while read line; do echo $line; done
transaction 1
$ 

यह सुनिश्चित करना कि एक परम नईलाइन है, सही और समझदार और उचित डिफ़ॉल्ट है। अन्य विकल्प में सभी शेल कोड को ऑडिट करने के लिए समय जानना और सम्‍मिलित करना शामिल है जो कि अंतिम नई लाइन की कमी वाले पाठ को छूता है, या पाठ की अंतिम पंक्ति को खोने का जोखिम उठाता है।

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