Dlaczego Vim dodaje nową linię? Czy to konwencja?

22

Jeśli otworzę Vima i itest<Esc>:wqpiszę, to otrzymam plik, który nie ma w Vimie nowych linii, ale wydaje się, że zawiera nowy wiersz w kodzie:

$ vim -u NONE test.txt
$ cat test.txt | hd
00000000  74 65 73 74 0a                    |test.|
00000005

Jeśli otworzę Vima i napiszę, itest<Return><Esc>:wqto otrzymam plik, który ma jedną nową linię w Vimie, ale dwie nowe linie w kodzie:

$ rm test.txt
$ vim -u NONE test.txt
$ cat test.txt | hd
00000000  74 65 73 74 0a 0a                 |test..|
00000006

Zauważ, że otwieram Vima za pomocą, -u NONEwięc nie jest używana konfiguracja lokalna. Zauważ też, że może to być związane z moim poprzednim pytaniem .

To są informacje o moim systemie:

$ uname -a
Linux awsAlpha 3.2.0-60-virtual #91-Ubuntu SMP Wed Feb 19 04:13:28 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
$ vim --version
VIM - Vi IMproved 7.3 (2010 Aug 15, compiled May  4 2012 04:25:35)
Included patches: 1-429
Modified by [email protected]
Compiled by buildd@

Mogę również potwierdzić dokładnie to samo zachowanie w tym systemie:

$ uname -a
Linux bruno 3.5.0-48-generic #72-Ubuntu SMP Mon Mar 10 23:18:29 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
$ vim --version
VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Oct 26 2012 16:45:33)
Included patches: 1-547
Modified by [email protected]
Compiled by buildd@

Dlaczego Vim dodaje nową linię? Czy to konwencja?

Oto wyjaśnienie dotyczące hdpolecenia zainstalowanego na serwerze Ubuntu Server:

$ man hd | head -4
HEXDUMP(1)            BSD General Commands Manual            HEXDUMP(1)

NAME
     hexdump, hd — ASCII, decimal, hexadecimal, octal dump
dotancohen
źródło
8
To wydaje się być konwencją. Oto jak je wyłączyć, jeśli chcesz. Oto historia tego.
jliv902

Odpowiedzi:

28

Konwencja dla plików tekstowych uniksowych jest taka, że ​​każda linia jest zakończona nową linią, a nowe linie są zakończeniami linii, a nie separatorami linii.

Kiedy Vim zapisuje bufor jako plik, kończy każdą linię sekwencją końca linii dla tego formatu pliku, który dla Uniksa jest nową linią. Widzieć

:help 'fileformat'

Jeśli używasz narzędzi przetwarzania tekstu w systemie Unix, najlepiej trzymać się tej konwencji. Jeśli jednak nie musisz wstawiać nowego wiersza na końcu ostatniego wiersza pliku, możesz to zrobić. Vim uważa takie pliki za „binarne”. Widzieć

:help 'binary'
:help edit-binary
garyjohn
źródło
1
och, to interesujące. Więc oprócz słynnego \ r \ n vs \ n. Windows używa separatorów linii, a unix używa terminatorów linii? i czy jest to gdziekolwiek udokumentowane? Wiem, że tutaj zdefiniowano to przypuszczalnie w odniesieniu do unixa. ISO / IEC 9899: 2011, sekcja § 7.21.2 Strumienie mówi: Strumień tekstowy to uporządkowana sekwencja znaków złożona w linie, każda linia składa się z zera lub więcej znaków plus nowy znak kończący -line znak "
barlop
ale gdzie udokumentowano, że system Windows używa separatora linii?
barlop
2

Vim nie dodaje niczego, czego sam tam nie umieściłeś.

Znak „nowej linii” nie jest „nową linią” i oba przykłady są całkowicie normalne:

  • w pierwszym plik zawiera tylko jedną linię, więc otrzymujesz jeden znak „nowej linii”,
  • w drugim plik zawiera dwa wiersze, więc otrzymujesz dwa znaki „nowego wiersza”.
romainl
źródło
2
Dodaje nowy wiersz. Przetestuj go w następujący sposób: printf "\x41" > /tmp/test.txtnastępnie sprawdź, czy ma on tylko pojedynczy znak „A” z xxd /tmp/test.txt. Teraz vim /tmp/test.txt<ENTER>:wq. Sprawdź ponownie, aby zobaczyć plik zawierający dwa bajty: „A \ n”.
Ruslan
Linie kończą się znakiem nowej linii. Masz jedną linię, więc masz jeden znak nowej linii.
romainl
Cóż, po printftym nie miałem już dobrze uformowanych „linii”. Po vimie mam jeden. Dodaje więc coś, czego tam nie umieściłem.
Ruslan
To, co printfnie jest linią, jeśli się nie dodasz \n. Będąc edytorem tekstu, Vim domyślnie zajmuje się liniami, a każdy tekst, który wstawisz do pliku, jest przynajmniej w linii, chyba że wyraźnie powiesz Vimowi, aby tego nie robił.
romainl
2

Niezakończone pliki tekstowe są złe z wielu powodów; oto taki, o którym jeszcze nie wspominałem:

W hipotetycznym świecie, w którym dopuszczalne są pliki tekstowe bez nowej linii, nie byłoby różnicy między plikiem zawierającym 0 linii a plikiem zawierającym 1 pustą linię. Oba byłyby reprezentowane przez plik 0-bajtowy.

Nie można zdecydować, ile wierszy znajduje się w pliku, byłoby złe.


źródło
Pliki tekstowe w systemach innych niż Unix zawierają zero lub więcej pełnych wierszy plus niekompletny wiersz zero lub więcej znaków. Pusty plik nie zawiera pustej linii; zawiera zero pełnych linii i częściową linię zerowych znaków. Gdzie jest dwuznaczność?
supercat
Ta „częściowa linia” jest nieprzyjemną koncepcją. Nie możesz mieć go gdziekolwiek poza końcem pliku i nie możesz utworzyć pliku, który nie ma „częściowej linii”. Dodaje więcej zerwania do łączenia plików - nawet jeśli wstawisz nowy wiersz między plikami, otrzymasz coś, co nie jest semantycznie równoważne oryginalnej parze plików (ponieważ z 2 plikami masz 2 częściowe linie, a jeden z nich stał się czymś inaczej.) Nieelegancka propozycja.
Fakt, że konkatenacja plików spowoduje, że jakakolwiek część wiersza na końcu pierwszego zostanie dołączona do następnego pliku, jest ogólnie trudna w przypadkach, w których oba pliki zawierają pełne linie (czasami może być użyteczne połączenie plików, które nie zawierają żadnych pełnych linii ), ale tak właśnie jest. Unix nie zabrania budowy plików tekstowych kończących się liniami częściowymi i wierzę, że łączenie takich plików będzie zachowywać się jak w MSDOS. Wydaje mi się, że różnica polega na tym, że wiele edytorów opartych na systemie DOS historycznie
uważało,
... który jest nieco identyczny ze starym (zarejestrowani użytkownicy wczesnych wersji PC-Write zostali poinstruowani, aby użyć go do otwarcia kopii pliku wykonywalnego, przejścia do trybu zastępowania, znalezienia określonego ciągu i zastąpienia go swoim numer seryjny!). Zmuszenie plików do kończenia się na nowych liniach podczas ich zapisywania naruszyłoby to ograniczenie.
supercat
2

Vim 8.0 zapewnia to teraz z fixeolopcją. W szczególności jeśli:

:set nofixeol

potem Vim nie doda końcowego znaku nowej linii na końcu ostatniego wiersza, jeśli plik jeszcze go nie miał.

Może to być wtyczka typu pliku lub nawet Twoja .vimrc .

(To jest poprawa na :set binary ponieważ wpływa tylko na końcowy znak podziału wiersza, a binaryjednocześnie zmienia wiele innych zachowań, których prawdopodobnie nie chcesz, chyba że faktycznie edytujesz plik binarny.)

Nowo utworzony plik będzie domyślnie nadal miał znak końca linii. Możesz to zmienić (i zamienić plik, który ma już końcowy nowy wiersz na nie posiadający go), wykonując dodatkowo:

:set noeol

Należy to ustawić specjalnie dla każdego pliku, który chcesz zmienić: ładowanie pliku do bufora zawsze będzie ustawione tak, eolaby pasowało do bieżącego stanu pliku.

Smylery
źródło
1

Za pomocą polecenia „j” możesz połączyć wszystkie linie w jedną.

Jeśli chcesz również usunąć LF lub CRLF z ostatniego wiersza, wykonaj następujące czynności w vi.

$ vi file
:set binary
:set noeol
:w!
:f          look for [noeol] on the status line
:q
Robert
źródło