Как искать многострочные текстовые файлы, содержащие набор слов (, например, AAA и (BBB | CCC )и ~DD )?

Вы должны добавить ; до того, как сделано, или поместите новую строку здесь.

for file in /dev/DataStage/myProject/source/TEST/MyFile_*.csv; do echo "Testing" ; done
9
19.07.2021, 23:34
3 ответа

На мой взгляд, ваше решение вполне подходит для этой задачи. Однако это медленно, потому что порождает 3 процесса на файл. Я считаю, что Awk здесь лучше подходит, потому что он позволит прочитать целую партию файлов (, как это разрешено ARG _MAX ), за один раз, используя {} +вместо {} \;.

GNU Awk:

find. -type f -exec gawk '
    BEGINFILE{c1=c2=c3=0}
    /AAA/       {c1=1}
    /BBB/||/CCC/{c2=1}
    /DDD/       {c3=1; nextfile}
    ENDFILE{if(c1 && c2 && !c3)print FILENAME}
' {} +

POSIX*:

find. -type f -exec awk '
    FNR==1{
        if(NR>1 && c1 && c2 && !c3)print f
        c1=c2=c3=0
        f=FILENAME
    }
    /AAA/       {c1=1}
    /BBB/||/CCC/{c2=1}
    /DDD/       {c3=1; nextfile}
    END{if(c1 && c2 && !c3)print f}
' {} +

*На самом деле, nextfileвсе еще не POSIX, но он был принят к следующему выпуску стандарта . Вы можете удалить его для соответствия POSIX issue 7; результат будет тот же, но с потерей производительности.


Примечание.:Awk выручает, если у него нет прав на чтение файла. В GNU Find просто добавьте флаг -readable, чтобы избежать этого. Если GNU Find недоступен, в качестве дополнительного фильтра можно использовать Test :

.
find. -type f -exec test -r {} \; -exec awk '
   ...
' {} +

Но запуск теста для каждого файла приводит к снижению производительности.


Дополнительная литература:

15
28.07.2021, 11:22

Вот альтернативный способ. Он работает, сначала создавая списки файлов, содержащих каждое отдельное слово :

.
find. -type f -exec grep -lF 'AAA' {} + > files_with_AAA
find. -type f -exec grep -lF 'BBB' {} + > files_with_BBB
...

Затем условия могут быть реализованы путем обработки списков:

grep -Ff files_with_BBB files_with_AAA   # AAA & BBB
grep -Fvf files_with_BBB files_with_AAA  # AAA & ~BBB
sort -u files_with_AAA files_with_BBB    # AAA | BBB

Если нужно оценить большое количество файлов и несколько выражений, это может быть быстрее, так как не нужно повторно сканировать каждый файл.

2
28.07.2021, 11:22

Мне было бы интересно увидеть сравнение времени с этими решениями, особенно для ripgrep , в котором реализована -параллельная обработка.

  1. СGNU grep
grep -rLZ 'DDD' | xargs -0 grep -lZ 'AAAA' | xargs -0 grep -lE 'BBB|CCCCC'

# if your search terms are literal strings
grep -rLZF 'DDD' | xargs -0 grep -lZF 'AAAA' | xargs -0 grep -lF -e 'BBB' -e 'CCCCC'
  1. С rg. Обратите внимание, что рекурсивный поиск включен по умолчанию, а некоторые файлы также игнорируются по умолчанию. Вам нужно использовать -u, если вы не хотите, чтобы файлы, подобные .gitignore, влияли на результаты. Используйте -uuдля дополнительного поиска скрытых файлов. Используйте -uuu, если вы хотите также искать двоичные файлы.
rg --files-without-match -0 'DDD' | xargs -0 rg -l0 'AAAA' | xargs -0 rg -l 'BBB|CCCCC'

# if your search terms are literal strings
rg --files-without-match -0F 'DDD' | xargs -0 rg -l0F 'AAAA' | xargs -0 rg -lF -e 'BBB' -e 'CCCCC'
  1. С rgмногострочным соответствием
rg -lUP '(?s)\A(?!.*DDD)(?=.*(BBB|CCCCC)).*AAAA'
1
28.07.2021, 11:22

Теги

Похожие вопросы