Подтвердить что ты не робот

Как найти файлы, которые не заканчиваются переводом строки/перевода строки?

Как я могу перечислить имена файлов с обычным текстом (.txt), которые не заканчиваются символом новой строки?

например: list (output) это имя файла:

$ cat a.txt
asdfasdlsad4randomcharsf
asdfasdfaasdf43randomcharssdf
$ 

и не выводить (выводить) это имя файла:

$ cat b.txt
asdfasdlsad4randomcharsf
asdfasdfaasdf43randomcharssdf

$
4b9b3361

Ответ 1

Используйте pcregrep, версию grep для Perl-совместимых регулярных выражений, которая поддерживает многострочный режим с использованием флага -M, который можно использовать для совпадения (или не совпадения), если в последней строке была новая строка:

pcregrep -LMr '\n$' .

В приведенном выше примере мы говорим о рекурсивном поиске (-r) в текущем каталоге (.), Перечисляя файлы, которые не соответствуют (-L) нашему многострочному (-M) регулярному выражению, которое ищет новую -M в конце файл ('\n$')

Изменение -L на -L приведет к списку файлов, в которых есть символы новой строки.

pcregrep можно установить на MacOS с помощью пакета homebrew pcre: brew install pcre

Ответ 2

Хорошо, это моя очередь, я даю ему попробовать:

find -type f -print0 | xargs -0 -L1 bash -c 'test "$(tail -c 1 "$0")" && echo "No new line at end of $0"'

Ответ 3

Попробуйте:

find -type f -exec sh -c '[ -z "$(sed -n "\$p" "$1")" ]' _ {} \; -print

Он будет печатать имена файлов, заканчивающиеся пустой строкой. Чтобы распечатать файлы, которые не заканчиваются пустой строкой, измените значение -z на -n.

Ответ 4

Если вы используете 'ack' (http://beyondgrep.com) в качестве альтернативы grep, вы просто запускаете это:

ack -v '\n$'

Он фактически ищет все строки, которые не совпадают (-v), в конце строки.

Ответ 5

Это kludgy; кто-то наверняка может сделать лучше:

for f in `find . -name '*.txt' -type f`; do
    if test `tail -c 1 "$f" | od -c | head -n 1 | tail -c 3` != \\n; then
        echo $f;
    fi
done

N.B. это отвечает на вопрос в заголовке, который отличается от вопроса в теле (который ищет файлы, которые заканчиваются на \n\n, я думаю).

Ответ 6

Это должно сделать трюк:

#!/bin/bash

for file in `find $1 -type f -name "*.txt"`;
do
        nlines=`tail -n 1 $file | grep '^$' | wc -l`
        if [ $nlines -eq 1 ]
                then echo $file
        fi
done;

Назовите его так: ./script dir

например. ./script /home/user/Documents/ → перечисляет все текстовые файлы в /home/user/Documents, заканчивающиеся на \n.

Ответ 7

Большинство решений на этой странице не работают для меня (FreeBSD 10.3 amd64). Ян Уилл Решение OSX почти всегда работает, но довольно сложно: - (

Существует простое решение, которое почти всегда работает: (если $f является файлом):

sed -i '' -e '$ a \' "$ f"

Существует серьезная проблема с решением sed: он никогда не дает вам возможность просто проверить (и не добавлять новую строку).

Оба вышеупомянутых решения не работают для файлов DOS. Я думаю, что большинство портативное/скриптовое решение, вероятно, самое легкое, который я разработал сам: -)

Вот этот элементарный sh script, который объединяет file/unix2dos/tail. В вы, вероятно, придется использовать "$ f" в кавычках и вывести хвостовой выход (встроенный в переменную оболочки с именем last) как \ "$ f \"

if file $f | grep 'ASCII text' > /dev/null; then
    if file $f | grep 'CRLF' > /dev/null; then
        type unix2dos > /dev/null || exit 1
        dos2unix $f
        last="`tail -c1 $f`"
        [ -n "$last" ] && echo >> $f
        unix2dos $f
    else
        last="`tail -c1 $f`"
        [ -n "$last" ] && echo >> $f
    fi
fi

Надеюсь, это поможет кому-то.

Ответ 8

Другая опция:

$ find . -name "*.txt" -print0 | xargs -0I {} bash -c '[ -z "$(tail -n 1 {})" ] && echo {}'

Ответ 9

Поскольку ваш вопрос имеет тег perl, я отправлю ответ, который его использует:

find . -type f -name '*.txt' -exec perl check.pl {} +

где check.pl следующее:

#!/bin/perl 

use strict;
use warnings;

foreach (@ARGV) {
    open(FILE, $_);

    seek(FILE, -2, 2);

    my $c;

    read(FILE,$c,1);
    if ( $c ne "\n" ) {
        print "$_\n";
    }
    close(FILE);
}

Этот perl script просто открывается, по одному за раз, файлы, переданные как параметры, и читает только следующий символ; если он не является символом новой строки, он просто распечатывает имя файла, иначе он ничего не делает.

Ответ 10

Этот пример работает для меня на OSX (многие из вышеперечисленных решений не выполнялись)

for file in `find . -name "*.java"`
do
  result=`od -An -tc -j $(( $(ls -l $file  | awk '{print $5}') - 1 )) $file`
  last_char=`echo $result | sed 's/ *//'`
  if [ "$last_char" != "\n" ]
  then
    #echo "Last char is .$last_char."
    echo $file
  fi
done

Ответ 11

Лучший вариант, который я смог придумать, это:

git grep --cached -Il '' | xargs -L1 bash -c 'if test "$(tail -c 1 "$0")"; then echo "No new line at end of $0"; exit 1; fi'

Здесь используется git grep, потому что в моем сценарии использования я хочу, чтобы файлы, переданные в ветку git, заканчивались переводом строки.

Если это требуется вне git-репо, вы, конечно, можете просто использовать вместо него grep.

grep -RIl '' . | xargs -L1 bash -c 'if test "$(tail -c 1 "$0")"; then echo "No new line at end of $0"; exit 1; fi'

Почему я использую grep? Потому что вы можете легко отфильтровать двоичные файлы с помощью -I.

Затем обычные xargs/tail вещь найдены в других ответах, с добавлением выхода с 1, если в файле нет перевода строки. Так что это может быть использовано в Githook перед фиксацией или CI.