Труба найти в grep -v

18

Я пытаюсь найти все файлы определенного типа, которые не содержат определенную строку. Я пытаюсь сделать это, отправив команду find в grep -v

пример:

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

Это не похоже на работу. Кажется, он просто возвращает все файлы, найденные командой find. В основном я пытаюсь найти все файлы .java, которые соответствуют определенному имени файла (например, оканчивается на «Pb», как в SessionPb.java), и в которых нет «extends SomethingSomething» внутри.

Я подозреваю, что я делаю это неправильно. Так как должна выглядеть команда?

Hyangelo
источник
Вы можете добавить то, что заставляет вас думать, что это не сработало. может быть, ваше выражение grep слишком явное? нужен '-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. Пожалуйста, прочтите документацию к findutils! (Я много работал над этим!)
Джеймс Янгман
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, хорошая работа)

Я понял, что вашему grep нужна либо опция -i, либо менее явный.

Попробуй команду по частям ... ДЕЙСТВИТЕЛЬНО ЛИ ВЫВОДНЫЕ имена файлов кажутся правильными?

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

Если это так, то, скорее всего, ваша проблема либо в том, что ваш шаблон поиска grep не соответствует (орфографическая ошибка? Это происходит!), Либо просто нет совпадений.

Абсолютный худший случай:

grep -riL "something" *

выполнит ОЧЕНЬ больше работы, ища все, но должно дать вам некоторый вывод.

lornix
источник
Я попробовал ваши модификации, но все еще не получил ожидаемого результата. Я постараюсь обновить вопрос, чтобы сделать его более понятным.
Hyangelo
Если автор вопроса просто хочет найти имена файлов, не должен ли grep быть 'grep -l -v'?
Брюс Эдигер
он ищет определенное содержимое в файлах * .java
lornix
xargs -0 grep -v "something something"в xargs -0 grep -v "something something" /dev/nullпротивном случае вы получите странные результаты, когда команда find не найдет подходящих файлов.
Джеймс Янгман
{Grin} да, где-то там логика запуталась. Ничего подобного множественному тесту с обратной ложной логикой, от которого у вас болит голова
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», который, казалось, работал, насколько я мог судить. Есть ли разница в этом синтаксисе с указанным в расширенной версии RegEx?
Hyangelo
@Hyangelo \s- это расширение GNU grep, которое, я думаю, является синонимом [[:space:]].
Жиль "ТАК - перестань быть злым"