Попытка найти три слова, которые встречаются в одном файле рекурсивно

Используйте арифметику вместо регулярного выражения:

if ! (( num >= 0 && num <= 100 ))

(Это предполагает, что num является числовым. Если вам также нужно убедиться, что $num является числовым, используйте регулярное выражение.)

2
27.07.2020, 12:34
4 ответа

Предположим, нам нужны имена файлов, содержащие fooи bar, но , а не baz. В этом случае:

find. -type f -exec gawk '
  BEGINFILE{a=b=c=0}
  /foo/{a=1} /bar/{b=1} /baz/{c=1;nextfile}
  ENDFILE{if(a && b && !c)print FILENAME}' {} +

[Поскольку вы работаете в Linux, я предполагаю, что у вас есть доступ к GNU awk (gawk ).]

Обратите внимание, что при таком подходе запускается как можно меньше вызовов awk и каждый файл читается только один раз. Никаких промежуточных файлов не требуется. Это должно быть эффективно.

Пример

Рассмотрим каталог с двумя файлами:

$ cat file1.eml 
foo and
bar only
$ cat file2.eml 
foo
and
bar
and
baz

Если мы запустим нашу команду,он создает ./file1.emlкак единственный файл, отвечающий требованиям:

$ find. -type f -exec gawk '
    BEGINFILE{a=b=c=0}
    /foo/{a=1} /bar/{b=1} /baz/{c=1;nextfile}
    ENDFILE{if(a && b && !c)print FILENAME}' {} +
./file1.eml

Как это работает

  • findрекурсивно собирает список обычных файлов и передает его gawk.

  • BEGINFILE{a=b=c=0}

    В начале каждого нового файла переменные a, bи cустанавливаются равными нулю (false ).

  • /foo/{a=1}

    Если какая-либо строка содержит foo, установите переменную aв единицу. (верно ).

  • /bar/{b=1}

    Если какая-либо строка содержит bar, установите переменную bв единицу. (верно ).

  • /baz/{c=1;nextfile}

    Если какая-либо строка содержит baz, установите переменную cв единицу. (верно ).

    После любого слова, которое нужно исключить, если оно найдено, например, bazв нашем примере, нет смысла читать файл дальше. Итак, мы запускаем nextfile, чтобы пропустить остальные строки и перейти сразу к ENDFILE.

  • ENDFILE{if(a && b && !c)print FILENAME}

    В конце каждого файла, если aи bи неc(в awk !логически -не )верны, выведите имя файла.

Не -GNU awk

Если в вашем awk нет хороших функций BEGINFILEи ENDFILE, таких как mawk, вам нужно запустить по одной awkдля каждого файла:

find. -type f -exec mawk '
  /foo/{a=1} /bar/{b=1} /baz/{c=1;exit}
  END{if(a && b && !c) print FILENAME}' {} \;

или (кончик шляпы:Эд Мортон):

awk 'FNR==1 { if (a && b && !c) print fname; fname=FILENAME; a=b=c=0 } /foo/{a=1} /bar/{b=1} /baz/{c=1}   END{if(a && b && !c) print FILENAME}' *.eml

или, с рекурсивным поиском:

find. -type f -exec awk 'FNR==1 { if (a && b && !c) print fname; fname=FILENAME; a=b=c=0 } /foo/{a=1} /bar/{b=1} /baz/{c=1}   END{if(a && b && !c) print FILENAME}' {} +
5
18.03.2021, 23:17

Попробуйте find -execсgrep -q:

find /my/path -name "*.eml" \
  -exec grep -F -q "word1" {} \; \
  -exec grep -F -q "word2" {} \; \
  -exec grep -F -q "word3" {} \; \
  ! -exec grep -F -q "word4" {} \; \
  -print
  • grep -qвозвращает только код состояния
  • Пропустите -Fиз grep, если вы хотите искать шаблоны вместо слов
  • Добавьте -wк grepдля соответствия только целым словам :соответствует word, но не someword.
  • findсвязывает команды -execи останавливается при сбое одной из них (когда grep -qвозвращает код ошибки)
2
18.03.2021, 23:17

Просто скопируйте и вставьте этот фрагмент кода в новый файл сценария bash, сохраните его и выполните chmod +x <file>, затем запустите его в своем терминале, чтобы получить список всех файлов, содержащих "foo" и "bar" и не содержат "rab" строки:

#!/bin/bash
function notcontain {
        for FILE in $(find. 2> /dev/null); do
                if ! grep "rab" $FILE > /dev/null 2>&1; then
                        echo $FILE
                fi
        done
}
    
for FILE in `notcontain`; do
        if grep "foo" $FILE > /dev/null 2>&1 | grep "bar" $FILE > /dev/null 2>&1; then
                echo $FILE
        fi
done

Надеюсь, это поможет:)

0
18.03.2021, 23:17

Вы можете использовать такой подход, как:

grep -rIlZe foo. |
  xargs -r0 grep -lZe bar |
  xargs -r0 grep -LZe baz |
  xargs -r0 cat > MyOutputFile

То есть передать список файлов, сгенерированных первым grepв xargs -r0, чтобы передать следующему grep, который уточняет список.

Обратите внимание на опцию -Lдля последнего grep, которая похожа на -l, за исключением того, что она сообщает о файлах, в которых не найдено совпадений, поэтому мы получаем файлы, содержащие fooи barи неbaz.

Нужны только -rи -Iили первый grep. Последние получат списки обычных файлов в качестве аргументов (с двоичными файлами, уже отфильтрованными -Iв первом grep), а не каталоги, для которых нужно rпросмотреть.

Это означает, что содержимое файлов может быть считано несколько раз, что не очень эффективно, но grepреализации, как правило, намного быстрее, чем реализации awk, а также тот факт, что, поскольку все 4 команды выше запускаются параллельно, часть этой обработки будет выполняться одновременно несколькими процессорами, а с данными, уже кэшированными в памяти, это, вероятно, будет быстрее, чем на основе awk-.

2
18.03.2021, 23:17

Теги

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