Как найти файлы, которые не содержат заданный шаблон строки?

536

Как мне найти файлы в текущем каталоге, которые не содержат слово foo(используя grep)?

Сентил Кумар
источник

Ответы:

818

Если у вашего grep есть опция -L(или --files-without-match):

$ grep -L "foo" *
ghostdog74
источник
1
Как указано в другом месте, ack помогает по умолчанию избегать файлов .svn (subversion).
ГуруМ
11
@GuruM Это можно сделать в GNU grep, экспортировав переменную GREP_OPTIONS='--exclude-dir=.svn --exclude-dir=.git': ^)
bufh
6
Или эквивалент с использованием ag :ag -L 'foo'
епископ
5
Работает как волшебство! Подсказка: используйте -rLвместо того, -Lчтобы сопоставлять подкаталоги
Ufos
1
@Larry - более чистый способ избежать проблем с глобализацией - это использовать «пустой» параметр long, например: grep -L 'foo' -- *Стандартные команды, которые используют длинные параметры, используют, --чтобы указать, что после этого пункта больше нет параметров.
Пэдди Ландау
45

Посмотрите на ack. Он .svnавтоматически исключает вас, предоставляет регулярные выражения Perl и представляет собой простую загрузку одной программы Perl.

Эквивалент того, что вы ищете, должен быть в ack:

ack -L foo
Энди Лестер
источник
24

Вы можете сделать это только с помощью grep (без поиска).

grep -riL "foo" .

Это объяснение параметров, используемых на grep

     -L, --files-without-match
             each file processed.
     -R, -r, --recursive
             Recursively search subdirectories listed.

     -i, --ignore-case
             Perform case insensitive matching.

Если вы используете l(в нижнем регистре), вы получите противоположное (файлы с совпадениями)

     -l, --files-with-matches
             Only the names of files containing selected lines are written
Адриан
источник
17

Следующая команда дает мне все файлы, которые не содержат шаблон foo:

find .  -not  -ipath '.*svn*' -exec  grep  -H -E -o -c  "foo"  {} \; | grep 0
Сентил Кумар
источник
4
Вы хотите изменить grep 0 в конце на grep 0 $ (в противном случае вы получите ошибочные совпадения для файлов, которые имеют символ 0 в имени файла).
clouseau
9
@clouseau в основном прав ... Тем не менее, grep '0$'файлы тоже должны быть кратны 10 строкам! Вам нужно grep ':0$'в конце проверить наличие явного ': 0' в конце строки. Тогда вы получите только файлы с нулевыми строками.
TrinitronX
В UNIX, на котором я работаю, не было версий find или grep с этими параметрами, поэтому мне пришлось воспользоваться командой «ack», предложенной в других комментариях.
KC Baltz
14

Следующая команда исключает необходимость поиска, чтобы отфильтровать svnпапки с помощью секунды grep.

grep -rL "foo" ./* | grep -v "\.svn"
user999305
источник
9

Вам действительно нужно:

find .  -not  -ipath '.*svn*' -exec  grep  -H -E -o -c  "foo"  {} \; | grep :0\$
Форрест Тиффани
источник
6

Мне повезло с

grep -H -E -o -c "foo" */*/*.ext | grep ext:0

Мои попытки grep -vтолько что дали мне все строки без "foo".

Джонни
источник
4

проблема

Мне нужно реорганизовать большой проект, который использует .phtmlфайлы для записи HTML с использованием встроенного кода PHP. Я хочу использовать шаблоны усов вместо. Я хочу найти любые .phtmlфайлы, которые не содержат строку, так new Mustacheкак они все еще должны быть переписаны.

Решение

find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$ | sed 's/..$//'

объяснение

Перед трубами:

найти

find . Поиск файлов рекурсивно, начиная с этого каталога

-iname '*.phtml'Имя файла должно содержать .phtml( iделает его без учета регистра)

-exec 'grep -H -E -o -c 'new Mustache' {}'Запустите grepкоманду на каждом из подходящих путей

Grep

-H Всегда печатайте заголовки файлов с выходными строками.

-E Интерпретировать шаблон как расширенное регулярное выражение (то есть заставить grep вести себя как egrep).

-o Печатает только совпадающую часть строк.

-c Только количество выбранных строк записывается в стандартный вывод.


Это даст мне список всех путей к файлам, оканчивающихся на .phtml, со счетчиком количества встречений строки new Mustacheв каждом из них.

$> find . -iname '*.phtml$' -exec 'grep -H -E -o -c 'new Mustache' {}'\;

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0
./app/MyApp/Customer/View/Account/studio.phtml:0
./app/MyApp/Customer/View/Account/orders.phtml:1
./app/MyApp/Customer/View/Account/banking.phtml:1
./app/MyApp/Customer/View/Account/applycomplete.phtml:1
./app/MyApp/Customer/View/Account/catalogue.phtml:1
./app/MyApp/Customer/View/Account/classadd.phtml:0
./app/MyApp/Customer/View/Account/orders-trade.phtml:0

Первый канал grep :0$фильтрует этот список, чтобы включить только строки, оканчивающиеся на :0:

$> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0
./app/MyApp/Customer/View/Account/studio.phtml:0
./app/MyApp/Customer/View/Account/classadd.phtml:0
./app/MyApp/Customer/View/Account/orders-trade.phtml:0

Второй канал sed 's/..$//'удаляет последние два символа каждой строки, оставляя только пути к файлам.

$> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$ | sed 's/..$//'

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml
./app/MyApp/Customer/View/Account/studio.phtml
./app/MyApp/Customer/View/Account/classadd.phtml
./app/MyApp/Customer/View/Account/orders-trade.phtml
Gruffy
источник
3

Если вы используете git, он ищет все отслеживаемые файлы:

git grep -L "foo"

и вы можете искать в подмножестве отслеживаемых файлов, если у вас включена ** подкаталогная подстановка ( shopt -s globstarв .bashrc, смотрите это ):

git grep -L "foo" -- **/*.cpp
Zak
источник
1

У моего grep нет опции -L. Я нахожу обходной путь для достижения этой цели.

Идеи:

  1. выгрузить все имена файлов, содержащих заслуженную строку, в txt1.txt.
  2. выгрузить все имена файлов в каталоге в txt2.txt.
  3. сделайте разницу между файлом 2 dump командой diff.

    grep 'foo' *.log | cut -c1-14 | uniq > txt1.txt
    grep * *.log | cut -c1-14 | uniq > txt2.txt
    diff txt1.txt txt2.txt | grep ">"
    
user6305682
источник
Я забываю команды, но вместо того, чтобы записывать имена файлов, вы можете фактически сделать diffмежду двумя выходными потоками (я думаю, что вы окружаете команды круглыми скобками, и где-то тоже есть угловая скобка), если ваши системы поддерживают это, что, я думаю, вопрос, так как он не поддерживаетgrep -L
Dexygen
1

find *20161109* -mtime -2|grep -vwE "(TRIGGER)"

Вы можете указать фильтр в «find» и строку исключения в «grep -vwE». Используйте mtime в find, если вам нужно фильтровать и измененное время.

zandeep
источник
Кажется, это показывает все строки без строки, OP запрашивает только имена файлов.
Бен Фармер
1

Открыть отчет об ошибке

Как прокомментировал @tukan, есть открытый отчет об ошибке для Ag относительно флага -L/ --files-without-matches:

Поскольку в отчете об ошибках имеется небольшой прогресс, на -Lуказанную ниже опцию не следует полагаться , пока ошибка не будет устранена. Вместо этого используйте различные подходы, представленные в этой теме. Цитирую комментарий к сообщению об ошибке [выделено мной]:

Есть какие-нибудь обновления по этому поводу? -Lполностью игнорирует совпадения в первой строке файла. Похоже, если это не будет исправлено в ближайшее время, флаг должен быть полностью удален, так как он фактически не работает так, как рекламируется вообще .


Серебряный поисковик - Ag (предполагаемая функция - см. Отчет об ошибке)

В качестве мощной альтернативы grepвы можете использовать Серебряный Искатель - Ag :

Инструмент поиска кода, похожий на ack, с акцентом на скорость.

Глядя на man ag, мы находим -Lили --files-without-matchesвариант:

...

OPTIONS
    ...

    -L --files-without-matches
           Only print the names of files that don´t contain matches.

Т.е. для рекурсивного поиска файлов, которые не совпадают foo, из текущего каталога:

ag -L foo

Чтобы искать только в текущем каталоге файлы, которые не совпадают foo, просто укажите --depth=0рекурсию:

ag -L foo --depth 0
dfri
источник
Время от времени это не удается из-за -Lошибки - github.com/ggreer/the_silver_searcher/issues/238
tukan
@tukan спасибо за приглашение. Я обновил ответ; выбрав не удалять ответ, а вместо этого открыть информацию об ошибке.
dfri
1

другая альтернатива, когда у grep нет опции -L (например, IBM AIX), только с grep и оболочкой:

for file in * ; do grep -q 'my_pattern' $file || echo $file ; done
JMD
источник
-4
grep -irnw "filepath" -ve "pattern"

или

grep -ve "pattern" < file

Команда выше даст нам результат, так как -v находит инверсию искомого шаблона

сойка
источник
1
Это печатает линии, которые не содержат шаблон. Вы можете добавить -lопцию, чтобы напечатать только имя файла; но это все еще печатает имена любого файла, который содержит любую строку, которая не содержит образец. Я полагаю, что ОП хочет найти файлы, которые не содержат строки, содержащей шаблон.
tripleee
Команда, которую вы предоставили, перечисляет файлы в «filepath» со всеми их строками, которые не содержат «pattern».
Апродан
-6

Следующая команда может помочь вам отфильтровать строки, содержащие подстроку "foo".

cat file | grep -v "foo"
walkerlin
источник
2
Это печатает строки, которые не совпадают, а не имена файлов, которые не содержат совпадений ни в одной строке. Чтобы добавить оскорбление травмы, это бесполезное использованиеcat .
tripleee