Я предполагаю, что все здесь знакомы с пословицей, что все текстовые файлы должны заканчиваться новой строкой. Я знал об этом «правиле» годами, но всегда задавался вопросом - почему?
file
unix
text-files
newline
Уилл Робертсон
источник
источник
Ответы:
Потому что так стандарт POSIX определяет строку :
Поэтому строки, не заканчивающиеся символом новой строки, не считаются фактическими. Вот почему некоторые программы имеют проблемы с обработкой последней строки файла, если он не завершен новой строкой.
При работе с эмулятором терминала у этого руководства есть по крайней мере одно серьезное преимущество: все инструменты Unix ожидают этого соглашения и работают с ним. Например, при объединении файлов с
cat
файлом, оканчивающимся символом новой строки, эффект будет другим, чем без:И, как и в предыдущем примере, также показано, что при отображении файла в командной строке (например, через
more
) файл с завершающей строкой приводит к правильному отображению. Неправильно завершенный файл может быть искажен (вторая строка).Для согласованности очень полезно следовать этому правилу - в противном случае работа с инструментами Unix по умолчанию потребует дополнительной работы.
Подумайте об этом по-другому: если строки не заканчиваются символом новой строки, сделать такие команды как
cat
полезные гораздо сложнее: как сделать команду для объединения файлов таким образом, чтобыb.txt
иc.txt
?Конечно, это решаемо, но вам нужно сделать использование
cat
более сложным (например, добавив позиционные аргументы командной строкиcat a.txt --no-newline b.txt c.txt
), и теперь команда, а не каждый отдельный файл, контролирует, как она вставляется вместе с другими файлами. Это почти наверняка не удобно.... Или вам нужно ввести специальный символ стража, чтобы отметить строку, которая должна быть продолжена, а не завершена. Что ж, теперь вы застряли в той же ситуации, что и в POSIX, за исключением инвертированного (продолжение строки, а не символ завершения строки).
Теперь, в не POSIX-совместимых системах (в настоящее время это в основном Windows), смысл спорный: файлы обычно не заканчиваются символом новой строки, и (неофициальное) определение строки может, например, быть «текстом, разделенным символами новой строки» (обратите внимание на акцент). Это полностью верно. Однако для структурированных данных (например, программного кода) это делает синтаксический анализ минимально более сложным: обычно это означает, что анализаторы должны быть переписаны. Если парсер изначально был написан с учетом определения POSIX, то может быть проще изменить поток токенов, чем синтаксический анализатор - другими словами, добавить токен «искусственной новой строки» в конец ввода.
источник
cat
полезные и непротиворечивые.Каждая строка должна заканчиваться символом новой строки, включая последнюю. В некоторых программах возникают проблемы с обработкой последней строки файла, если он не завершен новой строкой.
GCC предупреждает об этом не потому, что не может обработать файл, а потому, что это должно быть частью стандарта.
Справка: почтовый архив GCC / GNU .
источник
wc -l
не будет считать последнюю строку файла, если он не завершен новой строкой. Также,cat
объединит последнюю строку файла с первой строкой следующего файла в одну, если последняя строка первого файла не завершена новой строкой. Практически любая программа, которая ищет новые строки в качестве разделителя, может испортить это.wc
, уже упоминалось ....cat
иwc
)?Этот ответ является попыткой технического ответа, а не мнения.
Если мы хотим быть пуристами POSIX, мы определяем строку как:
Источник: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206
Неполная строка как:
Источник: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195
Текстовый файл как:
Источник: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397
Строка как:
Источник: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396
Из этого мы можем сделать вывод, что единственное время, когда мы потенциально можем столкнуться с проблемами любого типа, - это если мы имеем дело с концепцией строки файла или файла как текстового файла (поскольку текстовый файл является организацией с нулевым или больше строк, и известная нам строка должна заканчиваться символом <newline>).
Дело в точке:
wc -l filename
.Из
wc
руководства мы читаем:Каковы последствия для файлов JavaScript, HTML и CSS в том, что они являются текстовыми файлами?
В браузерах, современных IDE и других интерфейсных приложениях нет проблем с пропуском EOL в EOF. Приложения будут правильно анализировать файлы. Это связано с тем, что не все операционные системы соответствуют стандарту POSIX, поэтому было бы непрактично для инструментов, не относящихся к ОС (например, браузеров), обрабатывать файлы в соответствии со стандартом POSIX (или любым стандартом на уровне ОС).
В результате мы можем быть относительно уверены, что EOL в EOF практически не окажет негативного влияния на уровне приложений - независимо от того, работает ли он на ОС UNIX.
На данный момент мы можем с уверенностью сказать, что пропуск EOL в EOF безопасен при работе с JS, HTML, CSS на стороне клиента. На самом деле, мы можем утверждать, что минимизация любого из этих файлов, не содержащих <newline>, безопасна.
Мы можем сделать еще один шаг вперед и сказать, что в отношении NodeJS он также не может придерживаться стандарта POSIX, поскольку он может работать в средах, не поддерживающих POSIX.
Что же нам тогда осталось? Инструменты системного уровня.
Это означает, что единственные проблемы, которые могут возникнуть, связаны с инструментами, которые прилагают усилия, чтобы привязать их функциональность к семантике POSIX (например, определение строки, как показано на рисунке
wc
).Тем не менее, не все оболочки будут автоматически придерживаться POSIX. Например, Bash не использует POSIX по умолчанию. Существует переключатель , чтобы включить его:
POSIXLY_CORRECT
.Пищу для размышлений о ценности EOL, являющейся <newline>: https://www.rfc-editor.org/old/EOLstory.txt
Оставаясь на пути к инструменту, для всех практических целей и задач, давайте рассмотрим это:
Давайте работать с файлом, который не имеет EOL. На момент написания статьи файл в этом примере представлял собой уменьшенный JavaScript без EOL.
Обратите внимание, что
cat
размер файла является точно суммой его отдельных частей. Если конкатенация файлов JavaScript представляет собой проблему для файлов JS, более уместным было бы начинать каждый файл JavaScript с точки с запятой.Как кто-то еще упомянул в этой теме: что если вы захотите получить
cat
два файла, вывод которых станет одной строкой вместо двух? Другими словами,cat
делает то, что должен делать.man
Изcat
только упоминает чтение входных данных до EOF, а не <строки>. Обратите внимание, что-n
переключательcat
также выведет не завершенную <(новую строку>) строку (или неполную строку ) в виде строки, поскольку счет начинается с 1 (в соответствии сman
.)Теперь, когда мы понимаем, как POSIX определяет строку , это поведение становится неоднозначным или действительно несовместимым.
Понимание цели и соответствия данного инструмента поможет определить, насколько важно завершить файлы EOL. В C, C ++, Java (JAR) и т. Д. ... некоторые стандарты будут предписывать новую строку для валидности - для JS, HTML, CSS такого стандарта не существует.
Например, вместо того, чтобы использовать
wc -l filename
один, можно сделатьawk '{x++}END{ print x}' filename
, и будьте уверены, что выполнение задачи не будет поставлено под угрозу файлом, который мы можем захотеть обработать, который мы не записали (например, сторонней библиотекой, такой как минимизированный JS, который мыcurl
d) - если только наш Намерение было действительно посчитать строки в POSIX-совместимом смысле.Вывод
В реальных случаях будет очень мало случаев, когда пропуск EOL в EOF для определенных текстовых файлов, таких как JS, HTML и CSS, будет иметь негативное влияние - если вообще будет. Если мы полагаемся на присутствие <newline>, мы ограничиваем надежность наших инструментов только теми файлами, которые мы создаем, и открываем себя для потенциальных ошибок, допущенных сторонними файлами.
Мораль истории: Инженерные инструменты, у которых нет слабости полагаться на EOL в EOF.
Не стесняйтесь публиковать варианты использования, так как они относятся к JS, HTML и CSS, где мы можем изучить, как пропуск EOL отрицательно сказывается.
источник
Это может быть связано с разницей между :
Если каждая строка заканчивается концом строки, это позволяет избежать, например, того, что при объединении двух текстовых файлов последняя строка первого запуска переходит в первую строку второй.
Кроме того, редактор может при загрузке проверить, заканчивается ли файл концом строки, сохранить его в локальном параметре 'eol' и использовать его при записи файла.
Несколько лет назад (2005) многие редакторы (ZDE, Eclipse, Scite, ...) «забыли» эту последнюю версию EOL, которая не очень ценилась .
И не только это, но они неправильно интерпретировали этот конечный EOL как «начать новую строку» и фактически начали отображать другую строку, как если бы она уже существовала.
Это было очень хорошо видно в «правильном» текстовом файле с хорошим текстовым редактором, таким как vim, по сравнению с открытием его в одном из вышеуказанных редакторов. Он отображал дополнительную строку ниже реальной последней строки файла. Вы видите что-то вроде этого:
источник
Некоторые инструменты ожидают этого. Например,
wc
ожидает этого:источник
wc
этого не ожидает , поскольку он просто работает в рамках определения «линии» в POSIX, а не в интуитивном понимании «линии» большинством людей.wc -l
печати1
в обоих случаях, но некоторые люди могут сказать, что второй случай должен печатать2
.\n
терминатор строки, а не разделитель строк, как это делает POSIX / UNIX, то ожидать, что второй случай выведет 2, просто безумие.В основном есть много программ, которые не будут правильно обрабатывать файлы, если они не получат окончательный EOL EOF.
GCC предупреждает вас об этом, потому что это ожидается как часть стандарта C. (раздел 5.1.1.2 очевидно)
Предупреждение компилятора «Нет новой строки в конце файла»
источник
Это происходит с самых первых дней, когда использовались простые терминалы. Символ новой строки использовался для запуска «сброса» переданных данных.
Сегодня символ новой строки больше не требуется. Конечно, многие приложения по-прежнему имеют проблемы, если новой строки нет, но я бы посчитал это ошибкой в этих приложениях.
Однако, если у вас есть формат текстового файла, в котором вам требуется новая строка, простая проверка данных становится очень дешевой: если файл заканчивается строкой, в конце которой нет новой строки, вы знаете, что файл поврежден. Имея только один дополнительный байт для каждой строки, вы можете обнаружить битые файлы с высокой точностью и почти без использования процессорного времени.
источник
Отдельный вариант использования: когда ваш текстовый файл контролируется версией (в данном случае специально для git, хотя это относится и к другим). Если содержимое добавляется в конец файла, то строка, которая ранее была последней строкой, будет отредактирована для включения символа новой строки. Это означает, что
blame
в файле, чтобы узнать, когда эта строка была отредактирована в последний раз, будет показано добавление текста, а не фиксация до того, что вы действительно хотели увидеть.источник
\n
). Задача решена.В дополнение к вышеупомянутым практическим причинам, меня не удивило бы, если бы создатели Unix (Thompson, Ritchie, et al.) Или их предшественники Multics поняли, что есть теоретическая причина использовать терминаторы строки вместо разделителей строки: терминаторы, вы можете кодировать все возможные файлы строк. С разделителями строк нет никакой разницы между файлом нулевых строк и файлом, содержащим одну пустую строку; оба они закодированы как файл, содержащий ноль символов.
Итак, причины:
wc -l
не будет считаться окончательная «строка», если она не заканчивается новой строкой.cat
просто работает и работает без осложнений. Он просто копирует байты каждого файла без какой-либо интерпретации. Я не думаю, что есть эквивалент DOScat
. Использованиеcopy a+b c
приведет к слиянию последней строки файлаa
с первой строкой файлаb
.источник
Я сам удивлялся этому годами. Но я столкнулся с веской причиной сегодня.
Представьте себе файл с записью в каждой строке (например, файл CSV). И что компьютер писал записи в конце файла. Но это внезапно рухнуло. Ну и дела была последняя строка завершена? (не очень хорошая ситуация)
Но если мы всегда завершаем последнюю строку, мы бы знали (просто проверьте, завершена ли последняя строка). В противном случае нам, вероятно, придется каждый раз сбрасывать последнюю строку, чтобы быть в безопасности.
источник
Предположительно просто, что некоторый код синтаксического анализа ожидал, что это будет там.
Я не уверен, что считаю это «правилом», и я определенно не придерживаюсь этого принципа. Наиболее разумный код будет знать, как анализировать текст (включая кодировки) построчно (любой выбор конца строки), с новой строкой или без нее на последней строке.
Действительно - если вы заканчиваете новой строкой: есть ли (в теории) пустая конечная строка между EOL и EOF? Один задуматься ...
источник
Есть также практическая проблема программирования с файлами, в которых отсутствуют символы новой строки:
read
встроенный Bash (я не знаю о другихread
реализациях) не работает должным образом:Это только для
foo
печати ! Причина в том, что когдаread
встречается последняя строка, он записывает содержимое,$line
но возвращает код выхода 1, потому что он достиг EOF. Это нарушаетwhile
цикл, поэтому мы никогда не достигнемecho $line
части. Если вы хотите справиться с этой ситуацией, вы должны сделать следующее:То есть, делать,
echo
если произошелread
сбой из-за непустой строки в конце файла. Естественно, в этом случае будет одна дополнительная новая строка в выходных данных, которых не было во входных данных.источник
Как хорошо выражаются многие, потому что:
Многие программы плохо себя ведут или терпят неудачу без него.
Даже программы, которые хорошо обрабатывают файл, не имеют конца
'\n'
, функциональность инструмента может не соответствовать ожиданиям пользователя - что может быть неясно в этом случае.Программы редко запрещают финал
'\n'
(я не знаю ни одного).Тем не менее, напрашивается следующий вопрос:
Самое важное - не писать код, который предполагает, что текстовый файл заканчивается новой строкой . Предположение, что файл соответствует формату, приводит к повреждению данных, хакерским атакам и сбоям. Пример:
Если
'\n'
нужен последний трейлинг , предупредите пользователя об его отсутствии и предпринятых действиях. IOWs, проверьте формат файла. Примечание. Это может включать ограничение максимальной длины строки, кодировки символов и т. Д.Четко определите, документируйте, обработку кода отсутствующим финалом
'\n'
.Не, как это возможно, сгенерировать файл Недостатки концовки
'\n'
.источник
Здесь очень поздно, но я столкнулся с одной ошибкой в обработке файлов, которая возникла из-за того, что файлы не заканчивались пустым переводом строки. Мы обрабатывали текстовые файлы с помощью
sed
иsed
пропускали последнюю строку в выводе, что приводило к неверной структуре json и отправке остальной части процесса в состояние сбоя.Все, что мы делали, было:
Существует один пример файла
foo.txt
с некоторымjson
содержанием внутри него.Файл был создан на машине вдов, и оконные сценарии обрабатывали этот файл с помощью команд PowerShell. Все хорошо.
Когда мы обработали тот же файл с помощью
sed
командыsed 's|value|newValue|g' foo.txt > foo.txt.tmp
Недавно сгенерированный файл был
и бум, это не удалось остальные процессы из-за недопустимого JSON.
Поэтому всегда полезно заканчивать свой файл пустой новой строкой.
источник
У меня всегда было впечатление, что правило пришло со времен, когда анализ файла без завершающего перевода строки был трудным. То есть вы должны написать код, в котором конец строки определен символом EOL или EOF. Проще было предположить, что строка заканчивается EOL.
Однако я считаю, что правило основано на компиляторах C, требующих перевода строки. И, как указано в предупреждении компилятора «Нет новой строки в конце файла» , #include не будет добавлять новую строку.
источник
Представьте, что файл обрабатывается, пока файл еще генерируется другим процессом.
Это может быть связано с этим? Флаг, который указывает, что файл готов к обработке.
источник
Мне лично нравятся новые строки в конце файлов исходного кода.
Он может иметь свое происхождение от Linux или всех систем UNIX в этом отношении. Я помню там ошибки компиляции (gcc, если я не ошибаюсь), потому что файлы исходного кода не заканчивались пустой новой строкой. Почему так сделано, остается только удивляться.
источник
ИМХО, это вопрос личного стиля и мнения.
В старые времена я не ставил этот перевод строки. Сохраненный символ означает большую скорость через этот модем 14.4K.
Позже я поместил эту новую строку, чтобы легче было выбрать последнюю строку, используя shift + downarrow.
источник