Como passar os comandos combinados para encontrar -exec?

2

Qual é a sintaxe válida para passar os comandos combinados para find com a opção -exec ?

Exemplo:

find . -type f -name "*.txt" -exec grep FirstKeyWord {} | grep SecondKeyWord \;

falha com a seguinte mensagem de erro:

find: grep: missing argument to '-exec'
;: No such file or directory

O mesmo tipo de falha quando os comandos são combinados usando && ou ; em vez de | . Eu até tentei citar os comandos combinados com 'ou com $ () ou {} ou algo assim, mas ele (miseravelmente) falhou.

Observação: estou procurando uma solução de uma linha, sem usar scripts personalizados.

    
por Bludzee 09.09.2016 / 15:46

3 respostas

3

Você pode usar um comando shell complexo no argumento para exec, invocando explicitamente um shell lá.

find . -type f -name "*.txt" -exec sh -c 'grep FirstKeyWord "$1" | grep SecondKeyWord' -- {} \;

Isso executa sh com a lista de comandos fornecida para cada arquivo, passando o nome do arquivo em $1 .

EDIT: O OP indica que isso funciona e é mais simples:

find . -type f -name "*.txt" -exec sh -c 'grep FirstKeyWord {} | grep SecondKeyWord' \;
    
por 11.09.2016 / 15:16
2

Para o seu exemplo específico, você pode fazer isso:

find . -type f -name "*.txt" -exec grep FirstKeyWord {} \; | grep "SecondKeyWord"

BTW, isso também pode ser feito sem usar um segundo grep. Em vez disso, use egrep com as duas alternativas de FirstKeyWord seguido por SecondKeyWord ou SecondKeyWord seguido por FirstKeyWord :

find . -type f -name "*.txt" -exec egrep "FirstKeyWord.*SecondKeyWord|SecondKeyWord.*FirstKeyWord" {} \;

Se você puder fazer algumas garantias sobre os nomes de caminho resultantes do find (como nenhum espaço principal ou interno e nenhuma nova linha nos nomes de caminho), você também pode fazer desta forma:

find . -type f -name "*.txt" -print | while read filename; do grep "FirstKeyWord" "${filename}" | grep "SecondKeyWord"; done

A resposta mais geral é "você não pode" diretamente de find . Comandos de tubulação ou usando && ou || são uma função do shell, não uma função da execução de processos.

Eu já usei esse padrão antes, mas ele é frágil e mais complexo:

find . -type f -name "*.txt" -print \
    | sed -e 's;[\$"'!];\&;g' \
          -e 's;^.*$;grep "FirstKeyWord" "&" | grep "SecondKeyWord";' \
    | sh

Imprima cada nome de arquivo, use sed para transformá-lo em um shell script (tomando cuidado para escapar dos caracteres no nome do arquivo que podem causar problemas quando colocado entre aspas duplas) e execute o resultado o shell.

A outra solução é criar um script de shell que faça o seu processamento e chame esse script de shell a partir do find:

$ cat grepit.sh
#!/bin/sh
grep "FirstKeyWord" "$1" | grep "SecondKeyWord"
$ find . -type f -name "*.txt" -exec sh grepit.sh {} \;
    
por 09.09.2016 / 15:54
0

O uso de "-exec" é altamente desencorajado, porque cria muito subprocesso.

Por favor considere usar "find" com "xargs", (usando "-print0" e "-0")

find . -type f -name "*.txt" -print0 | xargs -0 grep FirstKeyWord | grep SecondKeyWord

Com isso, "grep" é gerado uma vez para muitos arquivos (até o limite do número de argumentos que um programa pode ter).

    
por 12.09.2016 / 11:32

Tags