При использовании систем контроля версий меня раздражает шум, когда говорит diff No newline at end of file
.
Поэтому мне было интересно: как добавить новую строку в конце файла, чтобы избавиться от этих сообщений?
bash
shell
text-processing
newlines
k0pernikus
источник
источник
Ответы:
Для рекурсивной очистки проекта я использую этот oneliner:
Объяснение:
git ls-files -z
перечисляет файлы в хранилище. Он принимает необязательный шаблон в качестве дополнительного параметра, который может быть полезен в некоторых случаях, если вы хотите ограничить операцию определенными файлами / каталогами. В качестве альтернативы вы можете использоватьfind -print0 ...
или аналогичные программы дляNUL
вывода списка затронутых файлов - просто убедитесь, что он генерирует неограниченное количество записей.while IFS= read -rd '' f; do ... done
перебирает записи, безопасно обрабатывая имена файлов, которые включают пробелы и / или переводы строк.tail -c1 < "$f"
читает последний символ из файла.read -r _
выходы с ненулевым статусом выхода, если завершающий символ новой строки отсутствует.|| echo >> "$f"
добавляет новую строку в файл, если состояние выхода предыдущей команды было ненулевым.источник
find -name \*.java | while read f; do tail -n1 $f | read -r _ || echo >> $f; done
git ls-files
который все равно спасет вас от редактирования файлов, которые не отслеживаются в системе контроля версий.IFS=
разделителя для сброса полезно для сохранения окружающих пробелов. Записи с нулевым символом завершения актуальны только в том случае, если у вас есть файлы или каталоги с новой строкой в названии, которая кажется несколько надуманной, но я согласен, что это более правильный способ обработки общего случая. Так же, как небольшое предупреждение:-d
опцияread
не доступна в POSIX sh.tail -n1 < "$f"
чтобы избежать проблем с именами файлов, которые начинаются с-
(tail -n1 -- "$f"
не работает для вызываемого файла-
). Вы можете уточнить, что ответ теперь зависит от zsh / bash.Вот, пожалуйста .
И в качестве альтернативы для OS X
sed
:Это добавляет
\n
в конец файла, только если он еще не заканчивается переводом строки. Так что, если вы запустите его дважды, он не добавит еще один символ новой строки:источник
man sed
:$ Match the last line.
Но, возможно, это работает только случайно. Ваше решение также работает.$
соответствует последней строке, почему он не добавляет еще одну новую строку в строку, которая уже содержит новую строку ?$
. Внутри регулярного выражения, например, с формой/<regex>/
, оно имеет обычное значение «совпадение конца строки». В противном случае, используемый в качестве адреса, sed дает ему специальное значение «последняя строка в файле». Код работает, потому что sed по умолчанию добавляет к выходу символ новой строки, если его там еще нет. Код «$ a \» просто говорит «соответствует последней строке файла и ничего не добавляет к нему». Но неявно sed добавляет новую строку к каждой строке, которую он обрабатывает (например, к этой$
строке), если ее там еще нет./regex/
дает другое значение. Я думаю, что страницыПосмотри:
так
echo "" >> noeol-file
надо делать свое дело. (Или вы хотели попросить идентифицировать эти файлы и исправить их?)edit удалил
""
изecho "" >> foo
(см. комментарий @yuyichao ) edit2""
снова добавил ( но см. комментарий @Keith Thompson)источник
""
не нужно (по крайней мере , для Баш) иtail -1 | wc -l
может быть использован , чтобы выяснить файл без новой строки в конце""
для bash это не обязательно, но я виделecho
реализации, которые ничего не печатают при вызове без аргументов (хотя ни одна из тех, что я могу найти сейчас, не делает этого).echo "" >> noeol-file
вероятно, немного более устойчивый.printf "\n" >> noeol-file
тем более.csh
«secho
это один известный выводить ничего , когда не передается никаких аргументов. Но тогда, если мы собираемся поддерживать не-подобные Борну оболочки, мы должны сделать этоecho ''
вместо того,echo ""
какecho ""
было бы""<newline>
сrc
илиes
например.tcsh
, в отличие от этогоcsh
, печатает новую строку, когда вызывается без аргументов - независимо от настройки$echo_style
.Другое решение с использованием
ed
. Это решение влияет только на последнюю строку и только если\n
отсутствует:По сути, это работает, открывая файл для редактирования через скрипт, скрипт - это единственная
w
команда, которая записывает файл обратно на диск. Это основано на этом предложении, найденном наed(1)
странице руководства:источник
Простой, переносимый, POSIX-совместимый способ добавить отсутствующий, последний символ новой строки в текстовый файл:
Этот подход не должен читать весь файл; он может просто стремиться к EOF и работать оттуда.
Этот подход также не требует создания временных файлов за вашей спиной (например, sed -i), поэтому жесткие ссылки не затрагиваются.
echo добавляет новую строку в файл, только когда результатом подстановки команды является непустая строка. Обратите внимание, что это может произойти, только если файл не пустой и последний байт не является новой строкой.
Если последний байт файла является новой строкой, tail возвращает его, а подстановка команд удаляет его; Результатом является пустая строка. Тест -n не проходит и эхо не запускается.
Если файл пуст, результатом подстановки команды также является пустая строка, и опять эхо не запускается. Это желательно, поскольку пустой файл не является недопустимым текстовым файлом и не является эквивалентом непустого текстового файла с пустой строкой.
источник
yash
если последний символ в файле является многобайтовым символом (например, в языковых стандартах UTF-8) или если языковым стандартом является C и для последнего байта в файле установлен 8-й бит. С другими оболочками (кроме zsh) он не добавил бы новую строку, если файл заканчивался байтом NUL (но опять же, это означало бы, что ввод будет нетекстовым даже после добавления новой строки).Добавить новую строку независимо от:
Вот способ проверить, существует ли новая строка в конце перед добавлением, используя Python:
источник
echo ""
кажется более надежным, чемecho -n '\n'
. Или вы могли бы использоватьprintf '\n'
Самое быстрое решение:
Это действительно быстро.
Для файла среднего размера
seq 99999999 >file
это занимает миллисекунды.Другие решения занимают много времени:
Работает в золах, баш, лкш, мкш, кш93, атш и зш, но не в яше.
Все остальные решения, представленные здесь, изменяют временную метку файла.
Если вам нужно решение, переносимое на yash (и все другие оболочки, перечисленные выше), оно может стать немного сложнее:
источник
Самый быстрый способ проверить, является ли последний байт файла новой строкой, - прочитать только этот последний байт. Это может быть сделано с
tail -c1 file
. Однако упрощенный способ проверить, является ли значение байта новой строкой, в зависимости от того, что оболочка обычно удаляет завершающую новую строку внутри расширения команды, не удается (например) в yash, когда последний символ в файле является UTF- 8 значение.Правильный, POSIX-совместимый, все (разумный) способ оболочки, чтобы определить, является ли последний байт файла новой строкой, должен использовать xxd или hexdump:
Затем, сравнение выходных данных выше
0A
обеспечит надежный тест.Полезно избегать добавления новой строки в пустой файл.
Файл, который не может предоставить последний символ
0A
, конечно:Коротко и сладко. Это занимает очень мало времени, так как он просто читает последний байт (ищите EOF). Неважно, если файл большой. Затем добавьте только один байт, если необходимо.
Временные файлы не нужны и не используются. Жесткие ссылки не затрагиваются.
Если этот тест будет выполнен дважды, он не добавит еще один символ новой строки.
источник
xxd
ниhexdump
утилиты. В инструментарии POSIX естьod -An -tx1
шестнадцатеричное значение байта.Вам лучше исправить редактор пользователя, который последний раз редактировал файл. Если вы последний, кто редактировал файл - какой редактор вы используете, я полагаю, textmate ..?
источник
emacs
не добавить новую строку в конце файла.(setq require-final-newline 'ask)
в моем.emacs
Если вы просто хотите быстро добавить новую строку при обработке какого-либо конвейера, используйте это:
это также POSIX-совместимый.
Тогда, конечно, вы можете перенаправить его в файл.
источник
cat file.csv | tr "\r" "\n" | { cat; echo; } | sed "/^[[:space:]]*$/d" | tail -n +2 | wc -l
При условии, что на входе нет нулей:
... было бы достаточно всегда добавлять новую строку в конец файла, если у него его еще нет. И это нужно только прочитать входной файл за один раз, чтобы получить его правильно.
источник
paste infile 1<> infile
вместо этого.Хотя это и не дает прямого ответа на вопрос, вот соответствующий сценарий, который я написал для обнаружения файлов, которые не заканчиваются переводом строки. Это очень быстро.
Сценарий perl читает список (необязательно отсортированных) имен файлов из stdin и для каждого файла читает последний байт, чтобы определить, заканчивается ли файл новой строкой или нет. Это очень быстро, потому что он избегает чтения всего содержимого каждого файла. Он выводит одну строку для каждого файла, который читает, с префиксом «error:», если возникает какая-либо ошибка, «empty:», если файл пустой (не заканчивается символом новой строки!), «EOL:» («конец line "), если файл заканчивается символом новой строки и" no EOL: ", если файл не заканчивается символом новой строки.
Примечание: скрипт не обрабатывает имена файлов, которые содержат переводы строк. Если вы работаете в системе GNU или BSD, вы можете обработать все возможные имена файлов, добавив -print0 для поиска, -z для сортировки и -0 для perl, например так:
Конечно, вам все равно придется придумать способ кодирования имен файлов с помощью новых строк в выходных данных (оставленных в качестве упражнения для читателя).
При желании выходные данные можно отфильтровать, чтобы добавить новую строку к тем файлам, у которых ее нет, проще всего с
Отсутствие последней строки может привести к ошибкам в сценариях, поскольку некоторые версии оболочки и другие утилиты не будут правильно обрабатывать отсутствующую последнюю строку при чтении такого файла.
По моему опыту, отсутствие последней новой строки вызвано использованием различных утилит Windows для редактирования файлов. Я никогда не видел, чтобы vim вызывал пропущенную последнюю строку при редактировании файла, хотя он будет сообщать о таких файлах.
Наконец, есть намного более короткие (но более медленные) сценарии, которые могут циклически проходить через входные имена своих файлов для печати тех файлов, которые не заканчиваются символом новой строки, например:
источник
В
vi
/vim
/ex
редакторы автоматически добавлять<EOL>
в EOF , если файл уже не имеет его.Так что попробуйте либо:
что эквивалентно:
Тестирование:
Чтобы исправить несколько файлов, проверьте: Как исправить «Нет новой строки в конце файла» для большого количества файлов? в СО
Почему это так важно? Чтобы наши файлы были совместимы с POSIX .
источник
Чтобы применить принятый ответ ко всем файлам в текущем каталоге (плюс подкаталоги):
Это работает в Linux (Ubuntu). На OS X вы, вероятно, должны использовать
-i ''
(не проверено).источник
find .
перечислены все файлы, включая файлы в.git
. Исключить:find . -type f -not -path './.git/*' -exec sed -i -e '$a\' {} \;
По крайней мере, в версиях GNU просто
grep ''
илиawk 1
канонизирует свой ввод, добавляя заключительный символ новой строки, если его еще нет. Они копируют файл в процессе, который занимает много времени, если он большой (но источник не должен быть слишком большим для чтения в любом случае?), И обновляет время мод, если вы не сделаете что-то вроде(хотя это может быть хорошо для файла, который вы регистрируете, потому что вы изменили его), и он теряет жесткие ссылки, разрешения по умолчанию, ACL и т. д., если вы не будете более осторожны.
источник
grep '' file 1<> file
, хотя это все равно будет читать и писать файл полностью.Это работает в AIX ksh:
В моем случае, если в файле отсутствует символ новой строки,
wc
команда возвращает значение,2
и мы записываем символ новой строки.источник
В дополнение к ответу Патрика Осцити , если вы просто хотите применить его к определенному каталогу, вы также можете использовать:
find -type f | while read f; do tail -n1 $f | read -r _ || echo >> $f; done
Запустите это внутри каталога, в который вы хотите добавить новые строки.
источник
echo $'' >> <FILE_NAME>
добавит пустую строку в конец файла.echo $'\n\n' >> <FILE_NAME>
добавит 3 пустых строки в конец файла.источник
Если ваш файл оканчивается на конец строки Windows,
\r\n
и вы находитесь в Linux, вы можете использовать этуsed
команду. Это только добавляет\r\n
к последней строке, если это еще не там:Объяснение:
Если последняя строка уже содержит a,
\r\n
то регулярное выражение поиска не будет совпадать, поэтому ничего не произойдет.источник
Вы могли бы написать
fix-non-delimited-line
скрипт как:Вопреки некоторым решениям, приведенным здесь, это
Вы можете использовать его, например, как:
или же:
POSIXly, вы можете сделать что-то функционально эквивалентное с
источник