Как исправить предупреждение «Нет новой строки в конце файла» для большого количества файлов? - PullRequest
10 голосов
/ 16 июля 2010

У меня есть огромное количество исходных файлов, в конце которых нет новой строки.

Как автоматически добавить новую строку в конце каждого из них?

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

Я, вероятно, не ищу код как таковой, а просто что-то, что я могу запустить в Терминале, чтобы добавить необходимые новые строки (или какой-то инструмент программирования или разработки).

Ответы [ 11 ]

7 голосов
/ 16 июля 2010

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

#!/bin/sh
for i
do
  if diff /dev/null "$i" | tail -1 | grep '^\\ No newline' > /dev/null
  then 
    echo >> "$i"
  fi
done

Я полагаюсь на diff, чтобы создать сообщение с \ в первом столбце, tail, чтобы дать мне последнюю строку вывода diff, и grep, чтобы сообщить мне, если последняя строка - это сообщение, которое я ищу. Если все это работает, то echo создает новую строку, а >> добавляет его в файл "$i". Кавычки вокруг "$i" гарантируют, что все будет работать, если в имени файла есть пробелы.

5 голосов
/ 01 февраля 2011

Преобразованный ответ Нормана в разделенную однострочную строку для удобства.

for i in * ; do  echo $i; \
 if diff /dev/null "$i" | tail -1 | \
  grep '^\\ No newline' > /dev/null; then echo >> "$i"; \
 fi; done

Замените * любым шаблоном файла, который вы хотите, например, *.c

И еще один, чтобы просто сказать вам, какие файлы сломаны:

for i in * ; do \
 if diff /dev/null "$i" | tail -1 | \
  grep '^\\ No newline' > /dev/null; then  echo $i; \
 fi; done
4 голосов
/ 25 июня 2017

Простое исправление для файлов, которые «пропускают» перевод строки в конце файла, просто sed; Следующее исправляет файл «на месте» (используя опцию «-i»):

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

Объяснение: найти все файлы (-type f), запустить sed, изменить файлы на месте (-i), используя следующий (-e) скрипт / выражение, которое соответствует концу файла ($) и выполните действие «добавить» (a\), но на самом деле не указывайте текст для добавления (ничего после \), который добавит новую строку в конец файла , но только если он отсутствует. Печатает все найденные файлы (фиксированные или нет), что, вероятно, не нужно.

Основная оговорка заключается в том, что функции sed различаются для разных платформ, поэтому -i и -e могут поддерживаться или не поддерживаться / одинаковы; например более ранние версии Unix или MacOS могут требовать немного другого синтаксиса.

3 голосов
/ 12 декабря 2012

ОК, после жалоб в комментариях, есть мое лучшее решение. Сначала вы хотите узнать, в каких файлах отсутствуют символы новой строки:

find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -v 0a$" ';' -print

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

Теперь, когда он у вас есть, вы также можете добавить новую строку с другим -exec:

find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -v 0a$" ';' -exec sh -c "echo >> {}" ';'

Возможные ошибки:

  • если имена файлов плохие, например у них есть пробелы, вам может понадобиться tail -1 \"{}\". Или найти сделать это правильно?

  • вы можете добавить дополнительные фильтры для поиска, например -name \*py и т. П.

  • перед использованием подумайте о возможной путанице в новых строках DOS / Unix (сначала исправьте).

EDIT:

Если вам не нравятся выходные данные этих команд (повторяя некоторые гексагоны), добавьте -q в grep:

find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -q -v 0a$" ';' -print
find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -q -v 0a$" ';' -exec sh -c "echo >> {}" ';'
1 голос
/ 27 мая 2017

Ниже мое решение для bash-скрипта. Сначала он проверяет, является ли файл текстовым файлом. Затем, если это текстовый файл, он использует tail и od (восьмеричный дамп), чтобы увидеть, является ли последний символ символом новой строки. Если это не так, тогда он добавляет новую строку, используя echo:

item="$1"

if file "$item" | egrep '\btext\b' > /dev/null
then
    if ! tail -c 1 "$item" | od -b -A n | egrep '\b012\b' > /dev/null
    then
        echo "(appending final newline to ${item})"
        echo >> "$item"
    fi
fi
1 голос
/ 24 февраля 2017

find -type f | while read f; do [[ `tail -c1 "$f"` ]] && echo >> "$f"; done

Я использую find вместо for f in *, поскольку это рекурсивно, и вопрос был об "огромном количестве исходных файлов".

Я использую while read вместо find -exec или xargs по соображениям производительности, это каждый раз сохраняет процесс запуска процесса.

Я пользуюсь тем фактом, что оператор backtick возвращает выходные данные команды «со всеми удаленными завершающими символами новой строки» man bash, поэтому для правильно завершенных файлов backtick будет пустым и эхо будет пропущено.

Пара find | read не будет работать с именами файлов, которые содержат символы новой строки, но это легко исправить, если требуется:

find -type f -print0 | while read -d $'\0' f; do [[ `tail -c1 "$f"` ]] && echo >> "$f"; done

1 голос
/ 16 мая 2015

Попробуйте ex-way:

ex -s +"bufdo wq" *.c

И рекурсивно (с включена новая опция глобализации ):

ex -s +"bufdo wq" **/*.c

Это эквивалентно vi -es,Измените *.c на расширение вашего интереса.

ex / vi автоматически добавит новую строку при сохранении, если ее нет.

0 голосов
/ 13 февраля 2017
pcregrep --recursive --exclude-dir=.git \
  --files-without-match --multiline '\n\z' . |
  while read k ; do echo >> "$k"; done

Здесь нужно выполнить несколько шагов:

  1. Рекурсивно находить файлы
  2. Определить, в каких файлах отсутствует завершающая новая строка
  3. Зацикливание каждого из этих файлов
  4. Добавить новую строку

Шаг 1 традиционно выполняется с find (в соответствии с традицией Unix «каждый инструмент делает одно и делает это хорошо»), но так как pcregrep имеет встроенную поддержку, мне удобно его использовать. Я стараюсь не возиться с папкой .git.

Шаг 2 выполняется с файлами соответствия многострочных регулярных выражений, которые do имеют последний перевод строки, и печатаются имена файлов, которые не соответствуют.

Шаг 3 выполняется с циклом while / read, а не для for / in, так как последний не подходит для имен файлов с пробелами и для очень длинных списков файлов.

Шаг 4 - простое эхо, следуя подходу @ norman-ramsey.

h / t @ anthony-bush https://stackoverflow.com/a/20687956/577438 для предложения pcregrep.

0 голосов
/ 29 августа 2015

Я удивлен, что никто не упомянул, что многие простые инструменты обработки текста, такие как Awk, добавят новую строку в качестве побочного эффекта.Вот простой цикл, который перезапишет файл, только если на самом деле был добавлен символ новой строки.

for f in *; do
    awk 1 "$f" >tmp
    cmp -s tmp "$f" || mv tmp "$f"
done
rm -f tmp

(временный файл, очевидно, немного бородавок.)

Демонстрация IDEone: http://ideone.com/HpRHcx

0 голосов
/ 28 августа 2015

После нахождения инструмента проделайте эту работу без удачи.Я решил написать свой собственный

Это мой скрипт на python для выполнения этой работы

Он только добавляет (\ r \ n) к файлу, который не содержит (\ n) в конце файла

https://github.com/tranhuanltv/append_newline

Использование: append_newline.py .c ./projects ./result_dir

Выполнять запросы на извлечение, если вы хотите

...