зачем пустая строка в конце файла
Почему важно всегда ставить символ переноса строки в конце текстовых файлов?
Иногда при просмотре диффов коммитов через git log или git diff можно заметить следующий вывод:
Или на GitHub в интерфейсе для просмотра диффов:
Почему это так важно, что Git и GitHub предупреждают нас об этом? Давайте разберемся.
Что такое символ переноса строки?
Что может быть проще, чем текстовый файл? Просто текстовые данные — как хранятся на диске, так и отображаются. На самом деле правительство нам врёт всё немного сложнее.
Оффтопик про управляющие символы ASCII
Не все символы, которые содержатся в текстовых файлах, имеют визуальное представление. Такие символы ещё называют «управляющими», и к ним относятся, например:
Многие эти символы пришли к нам из эпохи печатных машинок, поэтому у них такие странные названия. И действительно, в контексте печатной машинки или принтера такие операции, как перевод строки (сместить лист бумаги вверх так, чтобы печатающая головка попала на следующую строку), возврат каретки (переместить печатающую головку в крайнее левое положение) и возврат на один символ назад, обретают смысл. При помощи возврата на один символ назад создавались жирные символы (печатаешь символ, возвращаешься назад и печатаешь его ещё раз) и буквы с диакритическими знаками, такие как à или ã (печатаешь символ, возвращаешься назад и печатаешь апостроф или тильду). Но зачем печатной машинке бибикалка?
Сегодня многие из этих символов потеряли смысл, но некоторые до сих пор выполняют функцию, схожую с исходной.
Текстовые редакторы отображают текстовые файлы в некоем адаптированном виде, преобразуя непечатаемые символы, например, переносы строк и табуляции преобразуются в настоящие отдельные строки или выравнивающие отступы.
Для набора символа переноса строки достаточно нажать клавишу «Enter», но на разных платформах этот символ закодируется по-разному:
Как видите, Windows точнее всего эмулирует поведение печатной машинки.
Почему перенос строки в конце файла важен?
Согласно определению из стандарта POSIX, который тоже пришёл к нам из эпохи печатных машинок:
Строка — это последовательность из нуля или более символов, не являющихся символом новой строки, и терминирующего символа новой строки.
Почему важен этот стандарт? Возможен миллиард способов реализовать одно и то же, и только благодаря стандартам, таким как POSIX, мы имеем сейчас огромное количество качественного ПО, которое не конфликтует друг с другом.
Т.е. если вы не ставите символ переноса строки в конце строки, то формально по стандарту такая строка не является валидной. Множество утилит из Unix, которыми я пользуюсь каждый день, написано в согласии с этим стандартом, и они просто не могут правильно обрабатывать такие «сломанные» строки.
Давайте, например, через Python создадим такой файл со сломанными строками:
Упс! wc нашла только 2 строки!
Давайте создадим еще один файл:
И попробуем теперь склеить два созданных файла при помощи утилиты cat :
Название cat — это сокращение от «конкатенация», и никак не связано с котиками. А жаль.
И опять какой-то странный результат! В большинстве случаев это не то, чего вы бы ожидали, но вполне возможны ситуации, когда вам нужен именно такой результат. Именно поэтому утилита cat не может самостоятельно вставлять отсутствующие символы переноса строки, иначе это сделало бы её поведение неконсистентным.
Ещё доводы:
Настраиваем редактор
Самый простой способ перестать думать о пустых строках и начать жить — это настроить свой текстовый редактор или IDE на автоматическое добавление символа переноса строки в конец файлов:
Для других редакторов смотрите настройку здесь.
Заключение
Возможно, такая маленькая деталь, как перенос строки в конце файла и не кажется очень важной, а тема вообще кажется спорной, но боюсь, что у нас нет другого выбора, кроме как принять это правило за данность и просто выработать привычку (или настроить инструментарий) всегда ставить символ новой строки в любых текстовых файлах, даже если этого не требуется явно. Это считается распространённой хорошей практикой, и как минимум убережёт вас и ваших коллег от всяких неожиданных эффектов при работе с утилитами Unix.
В текстовом редакторе это выглядит как лишняя пустая строка в конце файла:
Почему рекомендуется иметь пустую строку в конце файла?
некоторые инструменты стиля кода рекомендуют это, и я помню, что видел некоторые инструменты командной строки unix, предупреждающие об отсутствии пустой строки.
каковы причины наличия дополнительной пустой строки?
7 ответов
многие старые инструменты плохо себя ведут, если последняя строка данных в текстовом файле не заканчивается новой строкой или комбинацией возврата каретки / новой строки. Они игнорируют эту строку, поскольку она заканчивается ^Z (eof).
помимо того, что это приятнее позицию курсора при перемещении в конец файла в текстовом редакторе.
с новой строки в конце файла обеспечивает простую проверку того, что файл не был усечен.
Если вы попытаетесь объединить два текстовых файла вместе, вы будете намного счастливее, если первый закончится символом новой строки.
пустая строка в конце файла появляется так, что стандартное чтение из входного потока будет знать, когда прекратить чтение, обычно возвращает EOF, чтобы указать, что вы достигли конца. Большинство языков могут обрабатывать маркер EOF. Именно по этой причине с давних времен, под DOS, маркером EOF была клавиша F6 или Ctrl-Z, для систем *nix это был Ctrl-D.
большинство, если не все, будет фактически читать вплоть до маркера EOF, так что библиотека времени выполнения функция чтения с входного сигнала будет знать, когда прекратить чтение дальше. Когда вы открываете поток для режима добавления, он будет стирать маркер EOF и писать мимо него, пока не будет явно вызвано закрытие, в которое он вставит маркер EOF в этой точке.
старые инструменты ожидали пустой строки, за которой следует маркер EOF. В настоящее время инструменты могут обрабатывать пустую строку и игнорировать ее.
аргумент также может быть сделан для более чистых различий, если вы добавляете в файл, следуя тем же рассуждениям, что и почему Python разрешает конечную запятую в списке?
некоторые языки определяют свой входной файл в терминах входных строк, где каждая входная строка представляет собой ряд символов, завершенных возвращением каретки. Если их грамматика определена таким образом, то последняя допустимая строка файла также должна быть завершена возвращением каретки.
Почему рекомендуется иметь пустую строку в конце исходного файла?
Некоторые инструменты стиля кода рекомендуют это, и я помню, как некоторые инструменты командной строки Unix предупреждали об отсутствии пустой строки.
В чем причина наличия лишней пустой строки?
Многие старые инструменты работают некорректно, если последняя строка данных в текстовом файле не заканчивается сочетанием новой строки или возврата каретки / новой строки. Они игнорируют эту строку, поскольку она заканчивается на ^ Z (eof).
Если вы попытаетесь объединить два текстовых файла вместе, вы будете намного счастливее, если первый из них закончится символом новой строки.
Помимо того факта, что это более приятная позиция курсора, когда вы перемещаетесь в конец файла в текстовом редакторе.
Наличие новой строки в конце файла обеспечивает простую проверку того, что файл не был усечен.
Аргумент может также быть сделан для более чистых различий, если вы добавляете в файл по тем же причинам Почему в списке допускаются конечные запятые?
Следующее скопировано (и немного обрезано) из связанного ресурса:
включает только однострочное изменение в diff:
Это лучше, чем запутанная многострочная разница, когда запятая не указана:
В конце файла появляется пустая строка, так что стандартное чтение из входного потока будет знать, когда прекратить чтение, обычно возвращает EOF, чтобы указать, что вы достигли конца. Большинство языков могут обрабатывать маркер EOF. Именно по этой причине в старые времена под DOS маркером EOF была клавиша F6 или Ctrl-Z, для * nix-систем это был Ctrl-D.
Большинство, если не все, на самом деле будут читать вплоть до маркера EOF, так что функция чтения во время выполнения библиотеки будет знать, когда прекратить чтение дальше. Когда вы открываете поток для режима добавления, он стирает маркер EOF и записывает его после него, пока явно не будет вызвано закрытие, в которое он вставит маркер EOF в этой точке.
Старые инструменты ожидали пустую строку, за которой следовал маркер EOF. В настоящее время инструменты могут обрабатывать пустую строку и игнорировать ее.
Некоторые языки определяют свой входной файл в терминах строк ввода, где каждая строка ввода представляет собой последовательность символов, оканчивающихся переводом каретки. Если их грамматика определена таким образом, то последняя действительная строка файла также должна заканчиваться переводом каретки.
Это из-за определения, что такое текстовый файл. Когда вы создаете новый текстовый файл в любой среде unix, содержимое этого файла представляет собой символ новой строки ‘\ n’
Почему рекомендуется иметь пустую строку в конце файла?
Некоторые инструменты стиля кода рекомендуют это, и я помню, как некоторые инструменты командной строки Unix предупреждали об отсутствии пустой строки.
В чем причина наличия лишней пустой строки?
Многие старые инструменты ведут себя неправильно, если последняя строка данных в текстовом файле не заканчивается сочетанием новой строки или возврата каретки/новой строки. Они игнорируют эту строку, поскольку она заканчивается на ^ Z (eof).
Помимо того факта, что это более приятная позиция курсора, когда вы перемещаетесь в конец файла в текстовом редакторе.
Наличие новой строки в конце файла обеспечивает простую проверку того, что файл не был усечен.
Если вы попытаетесь объединить два текстовых файла вместе, вы будете намного счастливее, если первый из них закончится символом новой строки.
Аргумент также может быть задан для более чистых разностей, если вы добавляете в файл по тем же соображениям, что и Почему Python допускает использование запятой в конце?
В конце файла появляется пустая строка, так что стандартное чтение из входного потока будет знать, когда прекратить чтение, обычно возвращает EOF, чтобы указать, что вы достигли конца. Большинство языков могут обрабатывать маркер EOF. Именно по этой причине в старые времена под DOS маркером EOF была клавиша F6 или Ctrl-Z, для * nix систем это был Ctrl-D.
Большинство, если не все, на самом деле будут читать вплоть до маркера EOF, так что функция чтения во время выполнения библиотеки будет знать, когда прекратить чтение дальше. Когда вы открываете поток для режима добавления, он стирает маркер EOF и записывает его после него, пока явно не будет вызвано закрытие, в которое он вставит маркер EOF в этой точке.
Старые инструменты ожидали пустую строку, за которой следовал маркер EOF. В настоящее время инструменты могут обрабатывать пустую строку и игнорировать ее.
Некоторые языки определяют свой входной файл в терминах строк ввода, где каждая строка ввода представляет собой последовательность символов, оканчивающихся переводом каретки. Если их грамматика определена таким образом, то последняя действительная строка файла также должна заканчиваться переводом каретки.
Это из-за определения, что такое текстовый файл. Когда вы создаете новый текстовый файл в любой среде unix, содержимое этого файла представляет собой символ новой строки ‘\ n’
Какой смысл добавлять новую строку в конец файла?
Некоторые компиляторы (особенно C или C ++) выдают предупреждения о:
Я думал, что это будет проблема только для C-программистов, но github отображает сообщение в коммит-представлении:
Какой смысл иметь новую строку в конце файла?
Речь идет не о добавлении новой строки в конце файла, а об удалении новой строки, которая должна быть там.
Утилиты, которые должны работать с текстовыми файлами, могут плохо работать с файлами, которые не заканчиваются символом новой строки; например, исторические утилиты Unix могут игнорировать текст после последней новой строки. Утилиты GNU придерживаются политики приличного поведения с нетекстовыми файлами, как и большинство других современных утилит, но вы все равно можете столкнуться со странным поведением с файлами, в которых отсутствует финальный символ новой строки¹.
Кстати, в контексте C исходный файл аналогичным образом состоит из серии строк. Точнее говоря, единица перевода рассматривается в реализации, определенной как последовательность строк, каждая из которых должна заканчиваться символом новой строки ( n1256 §5.1.1.1). В системах Unix отображение является простым. В DOS и Windows каждая последовательность CR LF ( \r\n ) отображается на новую строку ( \n это то, что всегда происходит при чтении файла, открытого как текст в этих ОС). Есть несколько ОС, которые не имеют символа новой строки, но вместо этого имеют записи фиксированного или переменного размера; в этих системах отображение из файлов на источник C вводит \n в конце каждой записи. Хотя это не имеет непосредственного отношения к unix, это означает, что если вы скопируете исходный файл C, в котором отсутствует заключительный символ новой строки, в систему с текстовыми файлами на основе записей, а затем скопируете ее обратно, вы либо получите неполное последняя строка усекается при первоначальном преобразовании или добавляется дополнительная строка при обратном преобразовании.
