У меня есть файлы в подкаталогах текущего каталога, которые могут иметь или не иметь новые строки в конце; Как мне найти файлы, в конце которых нет новой строки?
Я пробовал это:
find . -name '*.styl' | while read file; do
awk 'END{print}' $file | grep -E '^$' > /dev/null || echo $file;
done
но это не работает awk 'END{print}' $file
печатает строку перед пустой новой строкой, так же, как tail -n 1 $file
.
awk 'END{print}' $file
: это полностью игнорирует содержимое $ file, и после окончания анализа всех файлов, содержащихся в $ file, добавляет новую строку. Поскольку это единственная вещь, которую печатает команда awk, ее можно заменить на:printf '\n'
(без ментино $ file вообще) и сделать то же самое. Я думаю, что это НЕ то, к чему вы стремились (то есть: напечатать последнюю строку файла?)c
и FreeBSD, но я не заметил, что это задокументировано как зависящее от реализации: gnu.org/software/gawk/manual/… . Так что это произойдет , но не всегда.Ответы:
Чтобы уточнить,
\n
символ LF (он же или новая строка) - это разделитель строк , а не разделитель строк. Строка не заканчивается, если она не заканчивается символом новой строки. Файл, который содержит только,a\nb
не является допустимым текстовым файлом, поскольку он содержит символы после последней строки. То же самое для файла, который содержит толькоa
. Файл, который содержитa\n
одну непустую строку.Таким образом, файл, который заканчивается по крайней мере одной пустой строкой, заканчивается двумя символами новой строки или содержит один символ новой строки.
Если:
Вывод
\n
или\n \n
, то файл содержит хотя бы одну завершающую пустую строку. Если он ничего не выводит, то это пустой файл, если он выводит<anything-but-\0> \n
, то он заканчивается непустой строкой. Все остальное, это не текстовый файл.Теперь, чтобы использовать это для поиска файлов, оканчивающихся пустой строкой, хорошо, что это эффективно (особенно для больших файлов), поскольку оно считывает только последние два байта файлов, но сначала выходные данные не легко анализируются программно, особенно если учесть, что это не согласуется от одной реализации
od
к следующей, и нам нужно будет запускать однуtail
и однуod
на файл.(чтобы найти файлы, оканчивающиеся пустой строкой) будет запускать как можно меньше команд, но это будет означать чтение полного содержимого всех файлов.
В идеале вам нужна оболочка, которая может прочитать конец файла самостоятельно.
С
zsh
:источник
are_textfiles () { nontext=0; rem="return 0 if all args are files with terminating newline, or n [=number of non-textfiles]" ; for f in "$@" ; do [ -f "$f" ] && { tail -c 1 "$f" | od -An -vtc | grep "\\n" ;} >/dev/null 2>&1 || ((nontext++)) ; done ; return $nontext ; }
. Используйте как:if ( are_textfiles this that otherthing ) ; then echo all are text files ; else echo "are_textfiles returned : $?" ; fi
С
gnu sed
и оболочки вродеzsh
(илиbash
сshopt -s globstar
):это проверяет, является ли последняя строка каждого файла не пустой, если так, то печатает имя файла.
Если вы хотите наоборот (напечатать имена файлов, если последняя строка пуста), просто замените
/./
на/^$/
источник
-s
в действии раньше. Спасибо GNU!Правильно завершенный текстовый файл с пустой последней строкой заканчивается двумя
\n
.Затем мы ожидаем, что
tail -c2
должно быть равно$'\n\n'
.К сожалению, расширения команд удаляют завершающие новые строки. Нам нужно немного настроить.
Мы могли бы даже немного расширить, чтобы проверить, какие файлы не имеют новой строки:
Обратите внимание, что перевод строки может быть изменен на что-то вроде,
$'\r\n
если это необходимо.В этом случае также измените
tail -c2
наtail -c4
.источник
источник
cat $file 2>&1 /dev/null
, или , если это Bash-толькоcat $file &> /dev/null
.$file
везде, где это используется - и, пожалуйста, используйте$(commands ...)
вместо`backticks`
...