Знайдіть трубу в grep -v


18

Я намагаюся знайти всі файли певного типу та не містять певного рядка. Я намагаюся зробити це, пройшовши трубопровід до grep -v

приклад:

find -type f -name '*.java' | xargs grep -v "something something"

Це, здається, не працює. Здається, це просто повернення всіх файлів, знайдених командою find. Що я намагаюся зробити, це в основному знайти всі файли .java, які відповідають певному імені файлу (наприклад, закінчується "Pb", як у SessionPb.java), і у них немає "розширює SomethingSomething" всередині нього.

Моя підозра, що я роблю це неправильно. То як повинна виглядати команда замість цього?


Ви можете додати те, що вважає, що це не спрацювало. можливо, ваш виразний вираз занадто явний? потрібен '-i' для нечутливості випадку? Дивіться також мою відповідь нижче ...
lornix

Відповіді:


21

Тут немає потреби xargs. Крім того , необхідно використовувати grepз -Lпараметром (файли без матчу), викликають у іншому випадку він буде виводити вміст файлу замість його імені, як у вашому прикладі.

find . -type f -iname "*.java" -exec grep -L "something somethin" {} \+

1
-Lвже веде переговори, бо це означає files _without_ match. Тому тут вам не потрібен -vваріант.
пік

3
не з додатковою + в кінці.
lynxlynxlynx

2
@ user946850 кожен раз, коли я пишу, find -exec \+хтось пише мені, що набагато краще використовувати xargs. чому ніхто не виглядає людиною, перш ніж написати коментар? (:
пік

5
@ user946850 -exec ... {} \+не еквівалентно xargs. Прочитайте, будь ласка, документацію про завершення! (Я над цим багато працював!)
Джеймс Янгмен

2
@ user946850 так. Одна з відмінностей полягає в тому, що (за замовчуванням) xargsобробляє свій вхід і розділяє аргументи на пробіл. Котирування також є спеціальними (за замовчуванням) до xargs. Жодне з цих речей не відповідає дійсності -exec ... {} +. Старі версії xargsвикористовували для розгляду підкреслення як показник EOF, але це вже не так.
Джеймс Янгмен

7

Ви майже зрозуміли це справді ...

find . -type f -iname "*.java" -print0 | xargs -0 grep -v "something something"

Крапка "." каже почати звідси. (ваше це має на увазі .. але ніколи не припускайте).

-iname використовує нечутливий до регістру пошук, про всяк випадок (або про всяк випадок).
-print0 надсилає назви файлів xargs із заднім символом \ x00, що запобігає проблемам із файлами файлів у них пробілів.

'-0' на xargs говорить про очікування назви файлів, що закінчуються \ x00 замість повернень.

і ваша команда grep ...

Досить сильно це зрозуміло.


Редагувати ::

З вашого оновлення:

find . -type f -iname "*pb.java" -print0 | xargs -0 grep -iL "something"

повинні допомогти. (Додано -L з відповіді @ rush, хороша робота)

Мені здається, що ваш греп потребує або опції '-i', або бути менш явним.

Спробуйте команду по частинах ... ЦІ виводить імена файлів, які здаються правильними?

find . -type f -iname "*pb.java"

Якщо так, то ваша проблема, ймовірно, або ваша форма пошуку греп не відповідає (орфографічна помилка? Це трапляється!), Або просто немає відповідностей.

Абсолютний найгірший випадок:

grep -riL "something" *

зробимо багато більше роботи, шукаючи все, але вам слід дати деякий результат.


Я спробував ваші зміни, і я все одно не отримую очікуваного результату. Я спробую оновити питання, щоб було зрозуміліше.
Hyangelo

Якщо автор запитання просто хоче знайти імена файлів, чи не повинен grep бути "grep -l -v"?
Брюс Едігер

він шукає конкретний вміст у файлах * .java
lornix

xargs -0 grep -v "something something"в xargs -0 grep -v "something something" /dev/nullіншому випадку ви отримаєте дивні результати, коли файл пошуку не відповідає файлам.
Джеймс Янгмен

{Грін} так, десь там логіка все волохата. Нічого, як перевернута помилкова логічна множинна перевірка, щоб зробити голову боляче.
lornix

4

Комп'ютер є комп'ютером: він робить те, що ви йому наказали робити, а не те, що ви хотіли.

grep -v "something something"друкує всі рядки, які не містять something something. Наприклад, він друкує два рядки серед наступних трьох:

hello world
this is something something
something else

Щоб надрукувати файли, які extends SomethingSomethingніде не містять , скористайтеся -Lопцією:

grep -L -E 'extends[[:space:]]+SomethingSomething' FILENAME…

У деяких версіях grep немає -Lможливості (це не визначено POSIX ). Якщо у вас немає, нехай вона нічого не друкує, і використовуйте код повернення, щоб оболонка виклику робила все, що вона повинна робити замість цього.

grep -q -E 'extends[[:space:]]+SomethingSomething' FILENAME ||
echo "$FILENAME"

Крім того, використовуйте awk.

awk '
    FNR == 1 && NR != 1 && !found { print fn }
    FNR == 1 { fn = FILENAME; found = 0; }
    /extends[[:space:]]+SomethingSomething/ { found = 1 }
    END { if (fn != "" && !found) print fn }
'

Для Linux або Cygwin (або іншої системи з GNU grep) вам не потрібно використовувати find, оскільки grepце може повторюватися.

grep -R --include='*.java' -L -E 'extends[[:space:]]+SomethingSomething'

Якщо ваша оболонка - ksh, bash або zsh, ви можете змусити оболонку зробити ім'я файлу відповідним. На bash, запустіть set -o globstarспочатку (ви можете помістити це у свій ~/.bashrc).

grep -L -E 'extends[[:space:]]+SomethingSomething' **/*.java

Ух, це ще краще. Я використовував 'extends (/ s) + SomethingSomething', який, здавалося, працює наскільки я міг сказати. Чи є якась різниця у цьому синтаксисі з тими, які вказані у версії Extended RegEx?
Хіанжело

@Hyangelo \s- це розширення GNU grep, яке, на мою думку, є синонімом [[:space:]].
Жил "ТАК - перестань бути злим"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.