У меня проблемы с пониманием странного поведения: vi, кажется, добавляет новую строку (ASCII: LF, так как это система Unix ( 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.
Я ожидаю, что vi сохранит его «как есть», поэтому будет иметь 39 байтов: 10 символов ASCII в каждой из первых трех строк (цифры от 1 до 9, за которыми следует новая строка (LF в моей системе)) и только 9 в последней строка (символы от 1 до 9, без новой строки / LF).
Но появляется, когда я сохраняю его, это 40 байтов (вместо 39), и od показывает завершающий LF :
# 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?
Если я создаю файл с помощью printf, делая то же самое, что и в 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 символов) выглядят одинаково, если я снова открываю их с помощью ...
И если я открываю foo2 (39 символов, без завершающей строки) в vi и просто :wq
не редактирую его , он говорит, что записывает 40 символов, и появляется перевод строки!
У меня не может быть доступа к более новой версии vi (я делаю это в AIX, vi (не Vim ) версии 3.10, я думаю? (Без «-version» или других способов узнать это)).
# strings /usr/bin/vi | grep -i 'version.*[0-9]'
@(#) Version 3.10
Это нормально для vi (и, возможно, не в более поздней версии? Или Vim?), Чтобы тихо добавить новую строку в конце файла? (Я думал, что ~ указывает на то, что предыдущая строка НЕ заканчивалась символом новой строки.)
-
Изменить: некоторые дополнительные обновления и немного резюме, с большой благодарностью за ответы ниже:
vi тихо добавляет завершающий символ новой строки в тот момент, когда пишет файл, в котором его не было (если файл не пуст).
это происходит только во время написания! (т. е. до тех пор, пока вы: w, вы можете использовать: e, чтобы убедиться, что файл все еще находится в том же состоянии, в котором вы его открывали ... (т.е. он по-прежнему показывает "имя файла" [Последняя строка не завершена] N строка, символ M). Когда вы сохраняете, новая строка добавляется без предупреждения, без особого предупреждения (она говорит, сколько байтов она сохраняет, но в большинстве случаев этого недостаточно, чтобы знать, что была добавлена новая строка) (спасибо @jiliagre за то, что поговорили со мной о открыв сообщение vi, оно помогло мне найти способ узнать, когда действительно произойдет изменение)
Это (тихая коррекция) - поведение POSIX ! (см. @ barefoot-io answer для справок)
vi
версию или хотя бы понять ее происхождение, запустив:ve
команду.ex
страницу руководства, где:ver
обычно описывается команда.Ответы:
Это ожидаемое
vi
поведение.Ваш файл имеет неполную последнюю строку, так что строго говоря (т.е. в соответствии со стандартом POSIX), это не текстовый файл, а двоичный файл.
vi
это редактор текстовых файлов, а не двоичный, изящно исправляет его при сохранении.Это позволяет другим инструментам текстовых файлов
wc
,sed
таким как лайки, предоставлять ожидаемый результат. Обратите внимание, чтоvi
не стоит молчать об этой проблеме:Обратите внимание, чтобы получить некоторые подсказки о том, какую
vi
версию вы используете, вы можете использовать:ve
команду. Здесь видно, что я использую устаревший SVR4, определенно нетvim
:Судя по всему, ваш говорит:
Это, вероятно, означает, что AIX
vi
основан на исходном коде SVR3.В любом случае, это поведение и
[Incomplete last line]
предупреждающее сообщение были в унаследованномvi
исходном коде Билла Джоя с 1979 года и AFAIK, которые сохранялись во всех ветвях, созданных из выпусков исходного кода System V, из которых был создан проприетарный Unix, такой как AIX.Хронологически говоря, это поведение не является следствием соответствия POSIX, а скорее следствием первоначального решения Билла Джоя быть полезным для пользователей, редактирующих фиктивные текстовые файлы, а затем, спустя десятилетие, решение комитета POSIX сохранить этот допуск.
Если вы используете
ed
вместоvi
, вы заметите, что первый более подробный о проблеме, по крайней мере, если выed
из SVR3 или более новой ветви исходного кода:Также обратите внимание, что пустой файл является допустимым текстовым файлом, который содержит ноль строк. Поскольку в этом случае нет неопределенной строки для исправления,
vi
при сохранении файла не добавляется новая строка .источник
vi
как и OP, хотя на другом Unix. Это не тотvim
или иной клон. Ответ обновлен, чтобы уточнить это.vi
реализации. Возможно SVR3. Вы уверены, что[Incomplete last line]
при открытии файла сообщения нет?vi
реализацией AIX : www-01.ibm.com/support/docview.wss?uid=isg1IZ27694POSIX требует такого поведения, так что это не является чем-то необычным.
Из руководства по POSIX vi :
Следуя указаниям руководства POSIX ex :
Раздел ВЫХОДНЫЕ ФАЙЛЫ руководства vi также перенаправляет на ex:
Пара определений POSIX:
Эти определения в контексте этих выдержек из страницы руководства означают, что в то время как совместимая реализация ex / vi должна принимать искаженный текстовый файл, если единственной деформацией этого файла является отсутствующий заключительный символ новой строки, при записи буфера этого файла результатом должен быть действительный текстовый файл.
Хотя этот пост ссылается на выпуск стандарта POSIX 2013 года, соответствующие положения также появляются в гораздо более старой редакции 1997 года .
И наконец, если вы обнаружите, что бывшая новая версия приложения нежелательна, вы будете глубоко нарушены непереносимым изданием UNIX (1979) седьмого издания. Из руководства :
источник
ex
(не знаю его имени), я думаю, что спецификации POSIX настолько хороши, насколько можно ожидать. ;) Ближайший к «первоисточнику» к этому моменту, хотя это правда, они начинались как более или менее описания существующей функциональности.ex
была написана в соавторстве с Биллом Джоем и Чаком Элли ( web.cecs.pdx.edu/~kirkenda/joy84.html .) Я не подвергаю сомнению спецификации POSIX и тот факт, что текущиеvi
выпуски следуют этому, я просто заявляю о поведении долго предшествует этому.Я не припоминаю никакого другого поведения, когда в конце файла добавляется символ новой строки (используется
vi
с середины 80-х годов).~
Показывает , что линия на экране , который не является частью текста, а не о том , что файл не заканчивается символом новой строки. (Вам может быть трудно отследить ошибки, если вы поместите~
в последнюю строку сценариев оболочки). Если вы загрузите короткий файл с новой строкой в конце, вы увидите~
себя и опровергнете, что ваша мысль указывает на текст, не заканчивающийся переводом новой строки.источник
ed
) вы будете создавать строки и редактировать их, не добавляя символы. Я всегда думал о vi как о строковом редакторе. Но я понимаю ваше удивление.Текст, в котором неправильно отсутствует окончательный перевод строки через
while
цикл оболочки, приводит к тому, что последняя строка молча отбрасывается.Обеспечение окончательного перехода на новую строку - это правильное, нормальное и правильное значение по умолчанию. Другой вариант заключается в знании и наличии времени на аудит всего кода оболочки, который касается текста, в котором отсутствует окончательный перевод строки, или на риск потери последней строки текста.
источник