Pesquise vários padrões em um arquivo usando o comando find

Pesquise vários padrões em um arquivo usando o comando find

Existe uma opção para grep -f MY_FILEpermitir que ele procure padrões retirados de um arquivo, em vez de serem especificados diretamente na linha de comando.

Existe uma opção para fazer algo semelhante com o findcomando e deixá-lo ler os padrões para pesquisar em um arquivo de entrada?

Responder1

findnão parece ter esses recursos integrados, mas você pode usar xargspara construir vários findcomandos usando argumentos de um arquivo, como:

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

onde patterns.txtestaria uma lista de padrões adequados para o -namefiltro, um padrão por linha. Preste atenção para que você não tenha espaços iniciais/finais, pois eles seriam incluídos no padrão. Um exemplo:

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

Observação:Embora esta resposta pareça bastante fácil e elegante, foi corretamente apontado nos comentários que ela tem algumas desvantagens:

O desempenho não é muito bom para pastas grandes ou muitos padrões, pois ele será executado finduma vez por padrão em seu arquivo, fazendo com que ele verifique repetidamente toda a pasta de pesquisa.

Por causa disso, também se você tiver vários padrões que possam se sobrepor (como *.jpge *foo*), os arquivos que corresponderem a mais de um padrão aparecerão muitas vezes no resultado. Se você estiver apenas imprimindo os nomes de qualquer maneira, poderá canalizar a saída sort -upara remover duplicatas, mas se, por exemplo, remover esses resultados ou executar qualquer -execcomando neles, isso pode ser mais indesejável.

Se alguma dessas desvantagens for um problema para o seu caso de uso, talvez seja melhor optar por uma das respostas alternativas.

Explicação do comando:

  • xargsirá ler uma lista de argumentos e usá-los para construir e executar uma nova linha de comando.
  • -a patterns.txtdiz para ler esse arquivo em vez da entrada padrão.
  • -I%diz para ele não simplesmente anexar os argumentos lidos ao final da linha de comando, mas para substituir o %caractere na linha de comando que você forneceu por um argumento. Isto implica criar e executar um comando separado por argumento de entrada.
  • find Pictures/ -name %é a linha de comando na qual queremos inserir os argumentos, substituindo o %. Você não precisa citar aqui, porque xargscuidará para que cada argumento inserido seja tratado como token único e não seja dividido por conta própria. É claro que você pode substituir o Pictures/pelo seu próprio diretório de pesquisa e também usar filtros diferentes e/ou mais filtros além de apenas -name. Como usamos a opção de inserção, você também pode anexar ações como -exec ...no final do comando.

Responder2

Você pode simplesmente criar uma regex a partir do conteúdo do seu arquivo usando paste -sd'|' bar.

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

A regex será"^.*/(a|b)$"

Responder3

Não muito recentemente, fiz umresponderque combina vários padrões usando -regexsinalizador em find. Com base nisso, podemos fazer um pequeno script ou função para fazer o mesmo trabalho, mas construir a lista de padrões a partir do arquivo.

#!/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\).*$" 

O que isso faz:

  • chamamos script como findf.sh input.txt /etc, onde o primeiro parâmetro posicional é o arquivo com padrões e o segundo é o diretório onde pesquisar. GNU find assume .o diretório se o argumento do diretório for omitido, portanto $2não é obrigatório.
  • A função read_filelê o arquivo de entrada que é o primeiro parâmetro posicional do script. Isso cria um padrão para -regexa bandeira.
  • Esse padrão é repetido no bloco "principal" do script e salvo na fpvariável, e isso é passado para o findcomando.

informação relacionada