Как добавить новую строку в конец файла?

Используя системы контроля версий, меня раздражает шум, когда diff говорит No newline at end of file .

Поэтому мне было интересно: как добавить новую строку в конце файла, чтобы избавиться от этих сообщений?

18 Solutions collect form web for “Как добавить новую строку в конец файла?”

Для рекурсивной дезинфекции проекта я использую этот oneliner:

 git ls-files | while read f; do tail -n1 $f | read -r _ || echo >> $f; done 

Здесь вы идете :

 sed -i -e '$a\' file 

И, альтернативно, для OS X sed :

 sed -i '' -e '$a\' file 

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

 $ cd "$(mktemp -d)" $ printf foo > test.txt $ sed -e '$a\' test.txt > test-with-eol.txt $ diff test* 1c1 < foo \ No newline at end of file --- > foo $ echo $? 1 $ sed -e '$a\' test-with-eol.txt > test-still-with-one-eol.txt $ diff test-with-eol.txt test-still-with-one-eol.txt $ echo $? 0 

Взгляни:

 $ echo -n foo > foo $ cat foo foo$ $ echo "" >> foo $ cat foo foo 

поэтому echo "" >> noeol-file должен делать трюк. (Или вы хотели попросить идентифицировать эти файлы и исправить их?)

edit удалил "" из echo "" >> foo (см. комментарий @ yuyichao) edit2 добавил "" снова ( но см. комментарий @Keith Thompson)

Другое решение с использованием ed . Это решение влияет только на последнюю строку и только если \n отсутствует:

 ed -s file <<< w 

Он по существу работает над открытием файла для редактирования через скрипт, скрипт является единственной командой w , которая записывает файл обратно на диск. Он основан на этом предложении, найденном в ed(1) странице ed(1) :

 ОГРАНИЧЕНИЯ
        (...)

        Если текстовый (небинный) файл не заканчивается символом новой строки,
        затем ed добавляет один на чтение / запись.  В случае двоичного
        файл, ed не добавляет новую строку при чтении / записи.

Добавьте новую строку независимо:

 echo >> filename 

Вот способ проверить, существует ли новая строка в конце, прежде чем добавлять ее, используя Python:

 f=filename; python -c "import sys; sys.exit(open(\"$f\").read().endswith('\n'))" && echo >> $f 

Вам лучше исправить редактор пользователя, который в последний раз редактировал файл. Если вы последний человек, который отредактировал файл – какой редактор вы используете, я угадываю textmate ..?

Простой, портативный, совместимый с POSIX способ добавления отсутствующей, окончательной новой строки в текстовый файл:

 [ -n "$(tail -c1 file)" ] && echo >> file 

Этот подход не должен читать весь файл; он может просто искать EOF и работать оттуда.

Этот подход также не требует создания временных файлов за вашей спиной (например, sed -i), поэтому жесткие ссылки не затрагиваются.

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

Если последний байт файла является новой строкой, хвост возвращает его, а затем заменяет команду; результатом является пустая строка. Тест -n терпит неудачу, и эхо не выполняется.

Если файл пуст, результатом подстановки команды также является пустая строка, и снова эхо не запускается. Это желательно, поскольку пустой файл не является недопустимым текстовым файлом и не эквивалентен непустому текстовому файлу с пустой строкой.

Если во входных данных нет нулей:

 paste - <>infile >&0 

… было бы достаточно, чтобы всегда добавлять новую строку в хвост infile, если у нее ее еще не было. И нужно только прочитать входной файл за один раз, чтобы все было правильно.

Хотя он напрямую не отвечает на вопрос, вот связанный сценарий, который я написал, чтобы обнаружить файлы, которые не заканчиваются символом новой строки. Это очень быстро.

 find . -type f | # sort | # sort file names if you like /usr/bin/perl -lne ' open FH, "<", $_ or do { print " error: $_"; next }; $pos = sysseek FH, 0, 2; # seek to EOF if (!defined $pos) { print " error: $_"; next } if ($pos == 0) { print " empty: $_"; next } $pos = sysseek FH, -1, 1; # seek to last char if (!defined $pos) { print " error: $_"; next } $cnt = sysread FH, $c, 1; if (!$cnt) { print " error: $_"; next } if ($c eq "\n") { print " EOL: $_"; next } else { print "no EOL: $_"; next } ' 

Perl-скрипт считывает список (опционально отсортированных) имен файлов из stdin и для каждого файла он считывает последний символ, чтобы определить, заканчивается ли файл в новой строке или нет. Это очень быстро, потому что это позволяет избежать чтения всего содержимого каждого файла. Он выводит одну строку для каждого прочитанного файла с префиксом «error:», если возникает какая-то ошибка, «empty:», если файл пуст (не заканчивается символом новой строки!), «EOL:» («конец line "), если файл заканчивается символом новой строки и" no EOL: ", если файл не заканчивается символом новой строки.

Примечание: сценарий не обрабатывает имена файлов, которые содержат символы новой строки. Если вы работаете в Linux, вы можете обрабатывать все возможные имена файлов, добавляя -print0 для поиска, -z для сортировки и -0 для perl, например:

 find . -type f -print0 | sort -z | /usr/bin/perl -ln0e ' open FH, "<", $_ or do { print " error: $_"; next }; $pos = sysseek FH, 0, 2; # seek to EOF if (!defined $pos) { print " error: $_"; next } if ($pos == 0) { print " empty: $_"; next } $pos = sysseek FH, -1, 1; # seek to last char if (!defined $pos) { print " error: $_"; next } $cnt = sysread FH, $c, 1; if (!$cnt) { print " error: $_"; next } if ($c eq "\n") { print " EOL: $_"; next } else { print "no EOL: $_"; next } ' 

Конечно, вам все равно придется придумать способ кодирования имен файлов с новыми символами на выходе (слева как упражнение для читателя).

Вывод может быть отфильтрован, если необходимо, для добавления новой строки к тем файлам, у которых их нет,

  echo >> $filename 

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

По моему опыту, отсутствие окончательной новой строки вызвано использованием различных утилит Windows для редактирования файлов. Я никогда не видел, чтобы vim вызывал недостающую окончательную новую строку при редактировании файла, хотя он будет сообщать о таких файлах.

Наконец, существуют гораздо более короткие (но медленные) скрипты, которые могут перебирать входы в имена файлов, чтобы печатать те файлы, которые не заканчиваются в новой строке, например:

 /usr/bin/perl -ne 'print "$ARGV\n" if /.\z/' -- FILE1 FILE2 ... 

Если вы просто хотите быстро добавить новую строку при обработке некоторого конвейера, используйте это:

 outputting_program | { cat ; echo ; } 

он также совместим с POSIX.

Тогда, конечно, вы можете перенаправить его в файл.

Чтобы применить принятый ответ ко всем файлам в текущем каталоге (плюс подкаталоги):

 $ find . -type f -exec sed -i -e '$a\' {} \; 

Это работает на Linux (Ubuntu). На OS X вам, вероятно, придется использовать -i '' (непроверенный).

По крайней мере, в версиях GNU просто grep '' или awk 1 канонизирует свой вход, добавляя окончательную новую строку, если она еще не присутствует. Они копируют файл в процессе, который требует времени, если большой (но источник не должен быть слишком большим для чтения в любом случае?) И обновляет время, если вы не делаете что-то вроде

  mv file old; grep '' <old >file; touch -r old file 

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

Самый быстрый способ проверить, является ли последний байт файла символом новой строки, – это читать только последний байт. Это можно сделать с tail -c1 file . Тем не менее, упрощенный способ проверить, является ли значение байта новой строкой, в зависимости от оболочки обычное удаление завершающей новой строки внутри расширения команды не выполняется (например) в yash, когда последним символом в файле является UTF- 8.

Правильный, совместимый с POSIX, все (разумные) оболочки способ найти, если последний байт файла является новой строкой, это использовать либо xxd, либо hexdump:

 tail -c1 file | xxd -u -p tail -c1 file | hexdump -v -e '/1 "%02X"' 

Затем сравнение результата выше с 0A обеспечит надежный тест.
Полезно не добавлять новую строку в пустой файл.
Файл, который, конечно же, не сможет предоставить последний символ 0A :

 f=file a=`tail -c1 file | hexdump -v -e '/1 "%02X"'` [ -s "$f" -a "$a" != "0A" ] && echo >> "$f" 

Короткие и сладкие. Это занимает очень мало времени, так как он просто считывает последний байт (ищите EOF). Не имеет значения, большой ли файл. Затем добавьте только один байт, если необходимо.

Никакие файлы temp не нужны и не используются. На жесткие ссылки не влияет.

Если этот тест выполняется дважды, он не добавит еще одну новую строку.

Это работает в AIX ksh:

 lastchar=`tail -c 1 *filename*` if [ `echo "$lastchar" | wc -c` -gt "1" ] then echo "/n" >> *filename* fi 

В моем случае, если файл отсутствует в новой строке, команда wc возвращает значение 2 и мы пишем новую строку.

Редакторы vi / vim / ex автоматически добавляют <EOL> в EOF, если файл уже не имеет его.

Поэтому попробуйте либо:

 vi -ecwq foo.txt 

что эквивалентно:

 ex -cwq foo.txt 

Тестирование:

 $ printf foo > foo.txt && wc foo.txt 0 1 3 foo.txt $ ex -scwq foo.txt && wc foo.txt 1 1 4 foo.txt 

Чтобы исправить несколько файлов, проверьте: как исправить «Нет новой строки в конце файла» для большого количества файлов? на SO

Почему это так важно? Чтобы наши файлы совместимы с POSIX .

Много замечательных предложений здесь, но одна идея заключается в том, чтобы удалить новую строку и добавить ее, чтобы вы знали, что не добавляете их постоянно:

Возьмите файл «foo»:

Удалите новую строку, если она есть:

  truncate -s $(($(stat -c '%s' foo)-1)) foo 

Затем добавьте один:

  sed -i -e '$a\' foo 

Следовательно, foo всегда будет содержать хотя бы одну новую строку.

или хвост файла и искать новую строку, если она не содержит добавить один ..

  grep -q "[^0-9a-z-]" <<< $(tail -1 ./foo) && echo " " >> ./foo 

Добавляя ответ Patrick Oscity , если вы просто хотите применить его к определенному каталогу, вы также можете использовать:

find -type f | while read f; do tail -n1 $f | read -r _ || echo >> $f; done

Запустите это в каталоге, в который вы хотите добавить новые строки.

echo $'' >> <FILE_NAME> добавит пустую строку в конец файла.

echo $'\n\n' >> <FILE_NAME> добавит 3 пустые строки в конец файла.

  • Извлечь номер строки файла, который имеет ненулевое значение перед указанной строкой
  • Сгенерировать массив строк в сочетании с числом
  • Как переключиться из режима ввода в командный режим в ed?
  • Скрипт с использованием «split» в цикле над большими файлами
  • Как извлечь строки из текстового файла, который содержит строки из списка в другом файле?
  • Linux и Unix - лучшая ОС в мире.