Поиск нескольких шаблонов в файле с помощью команды find

Поиск нескольких шаблонов в файле с помощью команды find

Существует возможность grep -f MY_FILEпоиска шаблонов, взятых из файла, а не указанных непосредственно в командной строке.

Есть ли возможность сделать что-то подобное с findкомандой и позволить ей считывать шаблоны для поиска из входного файла?

решение1

findпохоже, не имеет таких встроенных возможностей, но вы можете использовать его xargsдля создания нескольких findкоманд с использованием аргументов из файла, например:

xargs -a patterns.txt -I% find Pictures/ -name %

где patterns.txtбудет список шаблонов, подходящих для -nameфильтра, по одному шаблону на строку. Обратите внимание, что там нет начальных/конечных пробелов, так как они будут включены в шаблон. Пример:

*.jpg
2018-06-*
*foo*
unicorn.png

Примечание:Хотя этот ответ выглядит довольно простым и элегантным, в комментариях справедливо отмечено, что у него есть несколько недостатков:

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

Из-за этого, также если у вас есть несколько шаблонов, которые потенциально могут перекрываться (например, *.jpgи *foo*), файлы, соответствующие более чем одному шаблону, будут появляться в результате столько же раз. Если вы в любом случае печатаете только имена, вы можете перенаправить вывод, sort -uчтобы удалить дубликаты, но если вы, например, удалите эти результаты или выполните какие-либо -execкоманды для них, это может быть более нежелательным.

Если какой-либо из этих недостатков является проблемой для вашего варианта использования, возможно, лучше выбрать один из альтернативных вариантов.

Пояснение к команде:

  • xargsпрочитает список аргументов и использует их для создания и запуска новой командной строки.
  • -a patterns.txtсообщает ему, что нужно читать из этого файла вместо стандартного ввода.
  • -I%говорит ему не просто добавлять прочитанные аргументы в конец командной строки, а заменить символ %в командной строке, который вы указали, одним аргументом. Это подразумевает создание и выполнение одной отдельной команды для каждого входного аргумента.
  • find Pictures/ -name %— это командная строка, в которую мы хотим вставить аргументы, заменив %. Здесь не нужно заключать в кавычки, поскольку xargsпозаботится о том, чтобы каждый вставляемый аргумент обрабатывался как отдельный токен и не разделялся сам по себе. Конечно, вы можете заменить Pictures/свой собственный каталог поиска, а также использовать другой и/или больше фильтров, чем просто -name. Поскольку мы используем опцию вставки, вы также можете добавлять действия, например, -exec ...в конец команды.

решение2

Вы можете просто создать регулярное выражение из содержимого вашего файла, используя paste -sd'|' bar.

find ~/foo -regextype egrep -regex "^.*/($(paste -sd'|' bar))$"

Регулярное выражение будет"^.*/(a|b)$"

решение3

Не так давно я сделалотвечатькоторый объединяет несколько шаблонов с помощью -regexфлага в find. На основе этого мы можем создать небольшой скрипт или функцию для выполнения той же работы, но составить список шаблонов из файла.

#!/bin/bash

read_file(){
    local full_pattern=""
    while IFS= read -r pattern; do
        if [ -z "$full_pattern"  ];then
            full_pattern="$pattern"
            continue
        fi
        full_pattern="$full_pattern\|$pattern"
    done < "$1"
    echo "$full_pattern"
}

fp=$(read_file "$1" )
find "$2" -type f -regex ".*\($fp\).*$" 

Что это делает:

  • мы вызываем скрипт как findf.sh input.txt /etc, где первый позиционный параметр - это файл с шаблонами, а второй - каталог, в котором нужно искать. GNU find предполагает .каталог, если аргумент каталога опущен, поэтому $2не требуется.
  • Функция read_fileсчитывает входной файл, который является первым позиционным параметром скрипта. Это создает шаблон для -regexфлага.
  • Этот шаблон возвращается обратно в «основной» блок скрипта и сохраняется в fpпеременной, которая затем передается в findкоманду.

Связанный контент