Добавляет ли vi незаметно новую строку (LF) в конец файла?

Поскольку имена файлов разделены новой строкой в ​​файле txtfile , вы можете читать каждый файл, проверьте, равно ли количество строк (или больше 20), если да, то напечатайте первые 20 строк, иначе напечатайте новые строки для оставшихся строк:

while IFS= read -r f; do 
    lines=$(wc -l <"$f")
    if (( lines < 20 )); then
        cat -- "$f" 
        for ((i=20; i>lines; i--)); do 
            echo
        done
    else 
        head -20 -- "$f"
    fi
done <txtfile
36
24.02.2016, 20:45
4 ответа

Это ожидаемое поведение 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 vi основана на SVR3. исходный код.

В любом случае, это поведение и предупреждающее сообщение [Incomplete last line] были в исходном коде vi старого Билла Джоя, по крайней мере, с 1979 года и AFAIK, сохраненных в все ответвления, созданные из выпусков исходного кода System V, из которых были построены проприетарные Unix, такие как AIX.

Хронологически говоря, такое поведение является не следствием соответствия POSIX, а, скорее, следствием первоначального решения Билла Джоя помогать пользователям редактировать поддельные текстовые файлы, а затем, десятилетие спустя, решение комитета POSIX сохранить этот допуск. .

Если вы используете ed вместо vi , вы заметите, что первое более подробно описывает проблему, по крайней мере, если ваше ed из SVR3 или более новая исходная ветка:

$ ed file
'\n' appended
8
q

Обратите внимание, что пустой файл - это допустимый текстовый файл, который может содержать ноль строк. Поскольку в этом случае нет незавершенной строки, которую нужно исправить, vi не добавляет новую строку при сохранении файла.

31
27.01.2020, 19:36

POSIX требует такого поведения, поэтому в этом нет ничего необычного.

Из руководства POSIX vi :

ВХОДНЫЕ ФАЙЛЫ

См. Раздел ВВОДНЫЕ ФАЙЛЫ команды ex для описания входных файлов, поддерживаемых командой vi.

По следам руководства POSIX ex :

ВХОДНЫЕ ФАЙЛЫ

Входные файлы должны быть текстовыми файлами или файлами, которые будут текстовыми файлами, за исключением неполной последней строки, длина которой не превышает {LINE_MAX} -1 байт в длину и не содержит символов NUL. По умолчанию любая неполная последняя строка должна обрабатываться так, как если бы она имела завершающую <новую строку>. Редактирование других форм файлов может опционально быть разрешено реализациями ex.

Раздел OUTPUT FILES руководства vi также перенаправляет на ex:

OUTPUT FILES

Результатом ex должны быть текстовые файлы.

Пара определений POSIX:

3.397 Текстовый файл

Файл, содержащий символы, сгруппированные в ноль или более строк. Строки не содержат символов NUL, и длина ни одной из них не может превышать {LINE_MAX} байтов, включая символ <новая строка>. Хотя POSIX.1-2008 не делает различий между текстовыми файлами и двоичными файлами (см. Стандарт ISO C), многие утилиты выдают предсказуемый или осмысленный вывод только при работе с текстовыми файлами. Стандартные утилиты с такими ограничениями всегда указывают «текстовые файлы» в своих разделах STDIN или INPUT FILES.

3.206 Строка

Последовательность из нуля или более символов, отличных от <новой строки>, плюс завершающий символ <новая строка>.

Эти определения в контексте этих выдержек из страниц руководства означают, что, хотя соответствующая реализация ex / vi должна принимать искаженный текстовый файл, если единственной деформацией этого файла является отсутствие последней строки новой строки, при записи в буфер этого файла результат должен быть допустимым. текстовый файл.

Хотя в этом посте есть ссылка на издание стандарта POSIX 2013 г., соответствующие положения также появляются в гораздо более старом издании 1997 г. .

Наконец, если вы сочтете добавление новой строки ex нежелательным, вы почувствуете себя глубоко нарушенным нетерпимым изданием UNIX (1979) седьмого издания. Из руководства :

При чтении файла ed отбрасывает символы ASCII NUL и все символы после последней новой строки. Он отказывается читать файлы, содержащие символы, отличные от ASCII.

51
27.01.2020, 19:36

Текст, в котором некорректно отсутствует последняя новая строка, прогоняется через цикл shell while, в результате чего последняя строка молча отбрасывается.

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

Обеспечение наличия конечной новой строки является правильным, здравым и надлежащим вариантом по умолчанию. Другой вариант подразумевает наличие знаний и времени для аудита всего кода shell, который касается текста, не имеющего конечной новой строки, или риск потерять последнюю строку текста.

1
27.01.2020, 19:36

Я не помню другого поведения, при котором новая строка добавлялась в конец файла (с использованием vi с середины 80-х).

~ указывает, что строка на экране не является частью текста, а не то, что файл не заканчивается новой строкой. (Вы можете затруднить отслеживание ошибок, если поместите ~ в последнюю строку сценариев оболочки). Если вы загрузите короткий файл с новой строкой в ​​конце, вы увидите ~ и опровергните, что, по вашему мнению, это означает текст, не заканчивающийся новой строкой.

1
27.01.2020, 19:36

Теги

Похожие вопросы