Bash scripting em um diretório do Maildir [duplicado]

0

Eu quero percorrer 500 arquivos em um diretório do Maildir. Eu emiti o comando

grep MyPattern *

Recebi a mensagem de erro:

bash: /usr/bin/grep: Argument list too long

Então eu armazenei a lista de arquivos em um arquivo MyFiles, e emiti o seguinte

for i in $('cat MyFiles'); do echo $i; done

Antes de fazer um grep, eu queria fazer um eco apenas como um cheque. Mas isso deu o seguinte erro

bash: 1434361691.M617282P6399V0000000000000808I00000000000E16C1_23.ananda-linux,S=10055:2,S: command not found

onde essa coisa 1434 ... é o primeiro arquivo no diretório.

Então, de volta à pergunta original. Como faço para grep todos esses arquivos na caixa de correio. E eu tenho caixas de correio maiores contendo 50000 ou mais e-mails.

    
por Sanjay Chakravarty 26.04.2018 / 10:02

2 respostas

1

Peça ao próprio grep para construir a lista de arquivos, recorrendo a partir do diretório atual:

grep -r MyPattern .

Isso não é exatamente o mesmo que * , já que ele pesquisará em subdiretórios, mas para diretórios de e-mail geralmente é o que você deseja.

    
por 26.04.2018 / 10:07
1

Quando o shell executa um comando externo, o comprimento da linha de comando, após a expansão de qualquer padrão de globalização de nome de arquivo, como * , não deve exceder um tamanho específico.

No seu caso, grep 'PATTERN' * expande para um comando muito longo para o shell executar.

No seu segundo exemplo:

for i in $('cat MyFiles'); do echo $i; done

você tenta fazer uma iteração sobre os nomes de arquivos armazenados em MyFiles , mas a sintaxe está muito errada.

$('cat MyFiles')

é o mesmo que

$( $(cat MyFiles) )

, o que significa que o conteúdo do MyFiles será interpretado como um comando. É por isso que você obtém o erro command not found .

Existem várias maneiras de corrigir isso, mas repetir o conteúdo do seu arquivo não é realmente bom.

Stephen dá uma boa solução em sua resposta , e outra seria, assumindo que seu diretório de trabalho atual é a sua pasta do Maildir,

find . -type f -exec grep 'PATTERN' {} +

Isso executaria grep algumas vezes em grandes lotes de arquivos possíveis .

Isso é semelhante a

printf '%s\n' * | xargs grep 'PATTERN'

mas o comando find lida com nomes de arquivos com espaços e novas linhas incorporadas.

O comando printf aqui irá gerar um nome de arquivo por linha. Ele não sofre do mesmo problema que grep 'PATTERN' * , já que é muito provável que seja um comando embutido e, portanto, não precisa ser executado como um comando externo pelo shell.

Sua solução de loop também funcionaria, mas em vez de executar um loop pela saída de cat , você poderia simplesmente fazer

for name in *; do
    grep 'PATTERN' "$name"
done

Isto assume que existem apenas arquivos regulares no diretório atual.

Para garantir que você processe apenas mensagens de e-mail, use

for name in *,*; do
    grep 'PATTERN' "$name" /dev/null
done

Isso itera sobre nomes que contenham pelo menos uma vírgula. Também adicionei /dev/null para forçar grep a gerar o nome dos arquivos que correspondem ao padrão fornecido. Você pode remover /dev/null e, em vez disso, usar -H com grep se o seu grep suportar isso.

Fazer um loop assim é lento, já que executamos grep uma vez para cada arquivo no diretório.

    
por 26.04.2018 / 11:14