grep não dando saída para um diretório passado em uma variável

grep não dando saída para um diretório passado em uma variável

Estou tentando escrever um bashscript que pesquisa o conteúdo dos arquivos em uma árvore de diretórios especificada em busca da presença de uma substring especificada.

Usar grepa função recursiva por si só não é suficiente, pois potencialmente preciso iterar no /diretório (e em todos os subdiretórios) de um sistema, o que faz com que grepfique sem memória e aborte. Portanto, decidi obter uma lista de todos os diretórios e subdiretórios na árvore de diretórios especificada usando findas seguintes variáveis ​​que denotam argumentos passados ​​para o script.

searchdir=$HOME     # passed in a script argument
searchstr="secret"  # passed in a script argument

Eu chamo o findutilitário e armazeno a saída em um arquivo temporário.

TF=$(mktemp)
find ${searchdir} -type d 1>$TF 2>/dev/null

Com a lista de todos os diretórios do arquivo temporário, procedo a iterar sobre as linhas deste arquivo utilizando um while-doloop com a intenção de realizar uma busca em todos os arquivos de cada diretório. Para grep, eu uso o formato dos parâmetros fornecidos emesta respostapara pesquisar todos os arquivos, inclusive os ocultos, em um único diretório.

cat $TF | while read line || [[ -n $line ]];
do
    grepdir="${line}/{*,.*}"
    grep -sHn "${searchstr}" ${grepdir}
done

... no entanto, esse código não produz saída.

Eu verifiquei isso...

O ${TF}contém a lista correta de todos os diretórios. A saída da ${grepdir}variável fornece a saída que espero encontrar.

/home/user/{*,.*}
/home/user/.ssh/{*,.*}
/home/user/test/{*,.*}
# ... and so on

Se eu executar o grepcomando com um diretório codificado, especialmente o ~/test/diretório que contém dois arquivos de teste com a string que ele deve encontrar

grep -sHn "${searchstr}" /home/user/test/{*,.*}

... gera corretamente os dois arquivos que contêm a substring "segredo".

/home/user/test/asdf:7:secret
/home/user/test/test.txt:5:asdfasfdsecretaasdfafd

Um formato que funciona para mim é aquele originalmente mencionado noresposta discutindo o uso recursivo degrep. Se eu fizer isso:

cat $TF | while read line || [[ -n $line ]];
do
    grep -rn "${line}" -e "${searchstr}"
done

... Recebo alguma saída (tecnicamente correta, mas com muitas entradas duplicadas), mas como grepestá processando os diretórios recursivamente e tenho uma lista de todos os diretórios, devo obter os mesmos resultados muitas vezes e em diretórios como como o diretório raiz mencionado acima grepfalhará completamente, e é isso que estou tentando evitar.


Provavelmente também devo mencionar que meus hacks desesperados para fazê-lo funcionar, como passar $(echo "${grepdir}")como parâmetro, também não levaram a nenhum resultado.

Provavelmente há um equívoco em meu pensamento ou compreensão de bash. Não deveria bashexpandir a ${grepdir}variável antes de fazer uma chamada para grep? Onde meu script está errado?

Responder1

Regra nº 1: quando um comando ou script não está fazendo o que você deseja, veja as mensagens de erro.  Não os jogue dentro  /dev/null.

Você está recebendo mensagens de erro como

grep: /home/user/{*,.*}: No such file or directory
grep: /home/user/.ssh/{*,.*}: No such file or directory
grep: /home/user/test/{*,.*}: No such file or directory

mas você não os está vendo.

Se olharmosfestança(1), Nós vemos

A expansão é executada na linha de comando após ser dividida em palavras. Existem sete tipos de expansão realizados: expansão de chaves, expansão de til, expansão de parâmetros e variáveis, substituição de comando, expansão aritmética, divisão de palavras e expansão de nome de caminho.

A ordem das expansões é: expansão de chaves; expansão de til, expansão de parâmetros e variáveis, expansão aritmética e substituição de comandos (feita da esquerda para a direita); divisão de palavras; e expansão do nome do caminho.

A parte importante para a sua situação é que a expansão das chaves ocorre antes da expansão da variável. Então, se você disse

grep -sHn "${searchstr}" "${line}"/{*,.*}

então

  • a expansão da chave transformaria o último token em "${line}"/*e "${line}"/.*,
  • expansão variável transformaria o acima em /home/user/*e /home/user/.*, e então
  • a expansão do nome do caminho transformaria o acima em uma lista de nomes de arquivos.

Mas, quando você diz

grep -sHn "${searchstr}" ${grepdir}

então

  • a expansão variável transforma o último token em /home/user/{*,.*},

e então é tarde demais para ocorrer a expansão do aparelho.  grepprocura um arquivo chamado literalmente /home/user/{*,.*}.


PS

grep -sHn "${searchstr}" "${line}/{*,.*}"

também não funcionaria, porque as aspas impediriam a ocorrência da expansão de chaves e do nome do caminho.

PPS Você não precisa de todos esses aparelhos;

grep -sHn "$searchstr" "$line"/{*,.*}

seria ótimo.

Responder2

A razão pela qual o grep é abortado ao recorrer em todo o sistema provavelmente não é porque ele não conseguiu lidar com a quantidade de dados, mas porque ele tropeça em um ou outro pseudo ou arquivo de dispositivo em/proc,/sys ou/dev. Você pode excluir os diretórios incorretos com a --excludeopção na linha de comando.

A razão pela qual não expande os curingas é porque eles estão citados nesta linha:

    grepdir="${line}/{*,.*}"

Mudá-lo para isso provavelmente ajudará na expansão.

    grepdir="${line}/"{*,.*}

Outra maneira de conseguir isso (com menos scripts em seu nome) seria selecionar os arquivos usando finde canalizando os caminhos dos arquivos xargspara processamento:find / ... -print 0 | xargs -0 ...

No entanto, de qualquer forma, provavelmente ainda tropeçaria em qualquer arquivo (s) em que o grep recursivo original tropeçou, a menos que você os exclua.

informação relacionada