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

Меню Search->Replace (или Ctrl+h). Заполните находят и заменяют поля, расширяются Replace All, нажать In Session

Пошаговый:

Выберите "Замену" из меню Search.

Select "Replace" from Search menu.

Расширьтесь, "заменяют все"

Expand "Replace All"

Нажмите "In Session"

Click "In Session"

195
18.02.2016, 19:06
21 ответ

Чтобы рекурсивно дезинфицировать проект, который я использую этот OneLiner:

git ls-files -z | while IFS= read -rd '' f; do tail -c1 < "$f" | read -r _ || echo >> "$f"; done

Объяснение:

  • GIT LS-файлы -Z перечислены файлы в репозитории. Это требует дополнительного шаблона в качестве дополнительного параметра, который может быть полезен в некоторых случаях, если вы хотите ограничить операцию определенным файлам / каталогам. В качестве альтернативы, вы можете использовать Найти -Print0 ... или аналогичные программы для списка пострадавших файлов - просто убедитесь, что он излучает Nul -DELIMID.

  • В то время как ifs = read -ird '' f; Делайте ... Готово , итерации через записи, безопасно обрабатывающие имена файлов, которые включают пробел и / или новые линии.

  • Хвост -C1 <«$ F» Читает последний символ из файла.

  • READ -R _ выходит с ненулевым состоянием выхода, если отсутствует трейлинг Newline.

  • || ECHO >> «$ F» добавляет новую строку в файл, если состояние выхода предыдущей команды было ненулевым.

45
27.01.2020, 19:28

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

4
27.01.2020, 19:28
  • 1
    Vim является рассматриваемым редактором. Но в целом, Вы правы, я должен не только зафиксировать symptons ;) –  k0pernikus 17.02.2012, 15:46
  • 2
    для энергии, необходимо стараться изо всех сил и сделать танец binary-file-on-save, чтобы заставить энергию не добавлять, что новая строка в конце файла - просто не делает того танца. ИЛИ, для простого исправления существующих файлов открывают их в энергии и сохранили файл, и энергия 'зафиксирует' недостающую новую строку для Вас (может быть легко задан сценарием для нескольких файлов), –  AD7six 17.02.2012, 15:50
  • 3
    Мой emacs не добавляйте новую строку в конце файла. –  enzotib 20.02.2012, 19:45
  • 4
    Спасибо за комментарий @AD7six я продолжаю получать фантомные отчеты от diffs, когда я фиксирую вещи, о том, как исходный файл не имеет новой строки в конце. Неважно, как я редактирую файл с энергией, я не могу заставить ее не помещать новую строку там. Таким образом, это - просто энергия, делающая его. –  Steven Lu 21.06.2013, 22:39
  • 5
    @enzotib: Я имею (setq require-final-newline 'ask) в моем .emacs –  Keith Thompson 19.02.2016, 20:59

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

ed -s file <<< w

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

LIMITATIONS
       (...)

       If  a  text (non-binary) file is not terminated by a newline character,
       then ed appends one on reading/writing it.  In the  case  of  a  binary
       file, ed does not append a newline on reading/writing.
16
27.01.2020, 19:28
  • 1
    Это не добавляет новую строку для меня. –  Olhovsky 12.04.2013, 04:46
  • 2
    Работы для меня; это даже печатает "Новую строку, добавленную" (ed-1.10-1 на Дуге Linux). огромное спасибо –  Stefan Majewsky 10.03.2015, 12:00

Посмотрите:

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

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

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

41
27.01.2020, 19:28
  • 1
    "" не необходимо (по крайней мере, для удара) и tail -1 | wc -l может использоваться для обнаружения файла без новой строки в конце –  yuyichao 17.02.2012, 16:42
  • 2
    @yuyichao: "" не необходимо для удара, но я видел echo реализации, которые ничего не печатают при вызове без аргументов (хотя ни один из тех я могу найти теперь, делают это). echo "" >> noeol-file вероятно, немного более устойчиво. printf "\n" >> noeol-file еще больше. –  Keith Thompson 17.02.2012, 19:17
  • 3
    @KeithThompson, csh echo одно известное ничего для вывода при отсутствии передачи никакой аргумент. Но затем если мы собираемся поддерживать неподобные границе оболочки, мы должны сделать его echo '' вместо echo "" как echo "" был бы ouput ""<newline> с rc или es например. –  Stéphane Chazelas 19.02.2016, 13:49
  • 4
    @StéphaneChazelas: И tcsh, в отличие от этого, csh, печатает новую строку при вызове без аргументов - независимо от установки $echo_style. –  Keith Thompson 19.02.2016, 20:55

Вот:

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
210
27.01.2020, 19:28
  • 1
    @jwd: От man sed: $ Match the last line. Но возможно это работает только случайно. Ваше решение также работает. –  l0b0 20.02.2012, 13:54
  • 2
    Ваше решение также более изящно, и я протестировал и фиксировал его, но как оно может работать? Если $ соответствует последней строке, почему она не добавляет другую новую строку к строке, которая уже содержит новую строку? –  l0b0 20.02.2012, 14:09
  • 3
    Существует два различных значения $. В regex, такой как с формой /<regex>/, это имеет обычный "конец соответствия строки" значение. Иначе, используемый в качестве адреса, sed дает ему специальную "последнюю строку в файле" значение. Код работает, потому что sed по умолчанию добавляет новую строку к своему выводу, если это уже не там. В коде "$a \" просто говорится, "соответствуют последней строке файла, и ничего не добавляют к нему". Но неявно, sed добавляет новую строку к каждой строке, которую это обрабатывает (такие как это $ строка), если это уже не там. –  jwd 22.02.2012, 21:07
  • 4
    Относительно страницы справочника: кавычка, к которой Вы обращаетесь, находится под разделом "Addresses". Вставление его /regex/ дает ему другое значение. Страницы справочника FreeBSD немного более информативны, я думаю: freebsd.org/cgi/man.cgi?query=sed –  jwd 22.02.2012, 21:15
  • 5
    Если файл уже заканчивается в новой строке, это не изменяет его, но он действительно переписывает его и обновляет его метку времени. Это может или не может иметь значения. –  Keith Thompson 19.02.2016, 21:01

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

echo >> filename

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

f=filename; python -c "import sys; sys.exit(open(\"$f\").read().endswith('\n'))" && echo >> $f
15
27.01.2020, 19:28
  • 1
    я не использовал бы версию Python ни в каком виде цикла из-за медленного времени запуска Python. Конечно, Вы могли сделать цикл в Python, если бы Вы хотели. –  Kevin Cox 09.11.2013, 16:03
  • 2
    Время запуска для Python составляет 0,03 секунды здесь. Вы действительно полагаете, что это проблематично? –  Alexander 10.11.2013, 13:48
  • 3
    Время Запуска действительно имеет значение, называете ли Вы Python в цикле, именно поэтому я сказал, рассматривают выполнение цикла в Python. Затем Вы только несете расходы запуска однажды. Для меня половина стоимости запуск является больше чем половиной времени целого snipit, я полагал бы что существенные издержки. (Снова, не важный, только делая небольшое количество файлов), –  Kevin Cox 11.11.2013, 18:35
  • 4
    echo "" кажется более устойчивым, чем echo -n '\n'. Или Вы могли использовать printf '\n' –  Keith Thompson 19.02.2016, 20:58

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

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 }
'

Сценарий жемчуга читает список (дополнительно отсортированный) имена файлов от stdin, и для каждого файла он читает последний байт, чтобы определить, заканчивается ли файл в новой строке или нет. Это очень быстро, потому что это старается не читать все содержание каждого файла. Это производит одну строку для каждого файла, который это читает, снабженный префиксом "ошибку": если некоторая ошибка происходит, "пустая": если файл пуст (не заканчивается новой строкой!), "EOL": ("конец строки"), если файл заканчивается новой строкой и "никаким EOL": если файл не заканчивается новой строкой.

Примечание: сценарий не обрабатывает имена файлов, которые содержат новые строки. Если Вы находитесь на GNU или системе BSD, Вы могли бы обработать все возможные имена файлов путем добавления-print0 для нахождения,-z к виду, и-0 к жемчугу, как это:

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 отредактировать файлы. Я никогда не видел, что энергия вызывает недостающую заключительную новую строку при редактировании файла, хотя она сообщит относительно таких файлов.

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

/usr/bin/perl -ne 'print "$ARGV\n" if /.\z/' -- FILE1 FILE2 ...
2
27.01.2020, 19:28

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

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

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

-1
27.01.2020, 19:28

Редакторы vi / vim / ex автоматически добавляют в 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 .

1
27.01.2020, 19:28

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

outputting_program | { cat ; echo ; }

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

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

3
27.01.2020, 19:28

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

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

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

0
27.01.2020, 19:28

При условии, что во входных данных нет нулей:

paste - <>infile >&0

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

3
27.01.2020, 19:28

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

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

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

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

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

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

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

12
27.01.2020, 19:28

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

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

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

0
27.01.2020, 19:28

Самый быстрый способ проверить, является ли последний байт файла новой строкой, - это прочитать только этот последний байт. Это можно сделать с помощью 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 "$f" | hexdump -v -e '/1 "%02X"')
[ -s "$f" -a "$a" != "0A" ] && echo >> "$f"

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

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

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

7
27.01.2020, 19:28

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

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

-2
27.01.2020, 19:28

Si su archivo termina con Windows finales de línea \r\ny está en Linux, puede usar este comando sed. Solo agrega \r\na la última línea si aún no está allí:

sed -i -e '$s/\([^\r]\)$/\1\r\n/'

Explicación:

-i    replace in place
-e    script to run
$     matches last line of a file
s     substitute
\([^\r]\)$    search the last character in the line which is not a \r
\1\r\n    replace it with itself and add \r\n

Si la última línea ya contiene un \r\n, la expresión regular de búsqueda no coincidirá, por lo tanto, no pasará nada.

-2
27.01.2020, 19:28

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

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

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

-2
27.01.2020, 19:28

Самое быстрое решение:

[ -n "$(tail -c1 file)" ] && printf '\n' >>file 

  1. Очень быстро.
    Для файла среднего размера seq 99999999 >fileэто занимает миллисекунды.
    Другие решения занимают много времени:

    [ -n "$(tail -c1 file)" ] && printf '\n' >>file  0.013 sec
    vi -ecwq file                                    2.544 sec
    paste file 1<> file                             31.943 sec
    ed -s file <<< w                             1m  4.422 sec
    sed -i -e '$a\' file                         3m 20.931 sec
    
  2. Работает в ash, bash, lksh, mksh, ksh93, attsh и zsh, но не в yash.

  3. Не изменяет временную метку файла, если нет необходимости добавлять новую строку.
    Все другие решения, представленные здесь, изменяют метку времени файла.
  4. Все приведенные выше решения действительны для POSIX.

Если вам нужно решение, переносимое на yash (и все другие оболочки, перечисленные выше ), это может немного усложниться:

f=file
if       [ "$(tail -c1 "$f"; echo x)" != "$(printf '\nx')" ]
then     printf '\n' >>"$f"
fi
10
27.01.2020, 19:28

Вы можете написать fix-non-delimited-lineскрипт типа:

#! /bin/zsh -
zmodload zsh/system || exit
ret=0
for file do
  if sysopen -rwu0 -- "$file"; then
    if sysseek -w end -1; then
      read -r x || print -u0
    else
      syserror -p "Can't seek in $file before the last byte: "
      ret=1
    fi
  else
    ret=1
  fi
done
exit $ret

В отличие от некоторых приведенных здесь решений,

  • должен быть эффективным в том смысле, что он не разветвляет ни один процесс, читает только один байт для каждого файла и не перезаписывает файл поверх (просто добавляет новую строку)
  • не нарушает символические/жесткие ссылки и не влияет на метаданные (также ctime/mtime обновляются только при добавлении новой строки)
  • должен работать нормально, даже если последний байт имеет значение NUL или является частью многобайтового символа -.
  • должно работать нормально независимо от того, какие символы или не -символы могут содержаться в именах файлов
  • Должен правильно обрабатывать нечитаемые, недоступные для записи или недоступные для поиска файлы (и сообщать об ошибках соответственно)
  • Не следует добавлять новую строку в пустые файлы (, но в этом случае сообщает об ошибке о недопустимом поиске)

Вы можете использовать его, например, как:

that-script *.txt

или:

git ls-files -z | xargs -0 that-script

POSIX, вы могли бы сделать что-то функционально эквивалентное с

export LC_ALL=C
ret=0
for file do
  [ -s "$file" ] || continue
  {
    c=$(tail -c 1 | od -An -vtc)
    case $c in
      (*'\n'*) ;;
      (*[![:space:]]*) printf '\n' >&0 || ret=$?;;
      (*) ret=1;; # tail likely failed
    esac
  } 0<> "$file" || ret=$? # record failure to open
done
0
27.01.2020, 19:28

Чтобы исправить все файлы в репозитории git, запустите

git ls-files --eol |\
 grep -e 'i/lf' |\
 grep -v 'attr/-text' |\
 sed 's/.*\t//' |\
 xargs -d '\n' sed -b -i -e '$a\'
  • git ls-files --eolсписок всех файлов, отслеживаемых git, с атрибутом eol
  • grep -e 'i/lf'отфильтровать файлы, зарегистрированные в индексе с помощьюLF
  • grep -v 'attr/-text'пропустить файлы, помеченные как binaryили -textв.gitattributes
  • sed 's/.*\t//'отфильтровать все, кроме путей
  • xargs -d '\n' sed -b -i -e '$a\'добавить новую строку в конец файла
    • -bобрабатывать файл как двоичный (не трогать концы строк)
    • -iредактирует файл на месте
    • -e '$a\'добавить новую строку в конец файла, но только если в конце файла нет новой строки и файл не пустой.
0
01.05.2021, 13:51

Теги

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