Используйте арифметику вместо регулярного выражения:
if ! (( num >= 0 && num <= 100 ))
(Это предполагает, что num является числовым. Если вам также нужно убедиться, что $num является числовым, используйте регулярное выражение.)
Предположим, нам нужны имена файлов, содержащие 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 !
логически -не )верны, выведите имя файла.
Если в вашем 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}' {} +
Попробуйте 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
возвращает код ошибки)Просто скопируйте и вставьте этот фрагмент кода в новый файл сценария 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
Надеюсь, это поможет:)
Вы можете использовать такой подход, как:
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
-.