Questão Como passar comandos combinados para encontrar -exec?


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


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

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

Nota: Estou procurando uma solução de uma linha, sem usar scripts personalizados.


1


origem


Na comunidade Stack Overflow, há uma pergunta semelhante: stackoverflow.com/questions/5119946/… - Bludzee
Na comunidade Super User, outra pergunta semelhante: superuser.com/questions/236601/… - Bludzee


Respostas:


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 $1.

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

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

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ê pode 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 || é uma função do shell, não uma função de execução de processos.

Eu usei este padrão antes, mas é 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 na hora (tomando cuidado para escapar dos caracteres no nome do arquivo que podem causar problemas quando colocados entre aspas duplas), então execute o resultado através do shell.

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

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

2



Em sua resposta de exemplo, se o nome do arquivo contiver "SecondKeyWord", mas não o conteúdo do arquivo, a linha será mantida enquanto deve ser filtrada. - Bludzee
Eu realmente preciso do segundo comando para ser combinado  para o primeiro comando para que eles se tornem um e único parâmetro -exec. - Bludzee
Esta é apenas uma solução alternativa para o exemplo específico. Eu gostaria de saber como passar comandos complexos (= combinados) para encontrar -exec, não apenas para usar o exemplo da pergunta. - Bludzee
Editado para responder à pergunta geral: você não pode; não diretamente de find. - J Earls


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).


0



Usando xargs é uma boa ideia para o exemplo, mas a questão é sobre find com -exec. BTW, você pode compartilhar um site de referência onde é explicado por que usar "-exec" seria "altamente desencorajado" (talvez um exagero)? - Bludzee
Apenas teste a diferença sozinho. Eu tenho 407 scripts de shell em vários diretórios. 17 segundos para: find '.sh '-exec grep' ^ # '' {} ''; ' ### mas 3 segundos para encontrar '.sh '-print0 | xargs -0 grep '# ^' - Vouze
Exec com + em vez de \; para lidar com vários parâmetros executa de forma semelhante ao xargs; não há necessidade de confundir o uso de exec no caso geral com uma proliferação de subprocessos.