Como faço para incluir um cachimbo | no meu comando linux find -exec?

220

Isso não está funcionando. Isso pode ser feito em busca? Ou preciso xargs?

find -name 'file_*' -follow -type f -exec zcat {} \| agrep -dEOE 'grep' \;
someguy
fonte

Respostas:

145

A tarefa de interpretar o símbolo de canal como uma instrução para executar vários processos e canalizar a saída de um processo para a entrada de outro processo é de responsabilidade do shell (/ bin / sh ou equivalente).

No seu exemplo, você pode optar por usar seu shell de nível superior para executar a tubulação da seguinte maneira:

find -name 'file_*' -follow -type f -exec zcat {} \; | agrep -dEOE 'grep'

Em termos de eficiência, esses resultados custam uma invocação de localização, inúmeras invocações de zcat e uma invocação de concordância.

Isso resultaria em apenas um único processo de aprovação que processaria toda a saída produzida por inúmeras invocações do zcat.

Se, por algum motivo, você desejar invocar o consentimento várias vezes, poderá:

find . -name 'file_*' -follow -type f \
    -printf "zcat %p | agrep -dEOE 'grep'\n" | sh

Isso constrói uma lista de comandos usando pipes para executar, depois os envia para um novo shell para realmente ser executado. (Omitir o "| sh" final é uma boa maneira de depurar ou executar execuções secas de linhas de comando como essa.)

Em termos de eficiência, esses resultados custam uma invocação de localização, uma invocação de sh, inúmeras invocações de zcat e inúmeras invocações de concordância.

A solução mais eficiente em termos de número de chamadas de comando é a sugestão de Paul Tomblin:

find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'

... que custa uma invocação de localização, uma invocação de xargs, algumas invocações de zcat e uma invocação de concordância.

Rolf W. Rasmussen
fonte
1
Outra vantagem do xargs seria que você pode acelerá-lo com a moderna CPU multi-core ainda mais, usando a opção -P (-P 0).
Flolo
Sim, a opção -P é realmente uma boa maneira de acelerar a execução em geral. Infelizmente, você corre o risco de a saída de processos zcat paralelos ser canalizada para o intercalado de acordo, o que afetaria o resultado. Este efeito pode ser demonstrado usando: echo -e "1 \ n2" | xargs -P 0 -n 1 sim | uniq
Rolf W. Rasmussen
@ Adam, eu fiz sua alteração sugerida.
Paul Tomblin
para o qual você pode instalar o comando xjobs esplêndida (originalmente de Solaris)
sehe
4
A resposta mais simples e mais geral é a stackoverflow.com/a/21825690/42973 : -exec sh -c "… | … " \;.
Eric O Lebigot
278

a solução é fácil: execute via sh

... -exec sh -c "zcat {} | agrep -dEOE 'grep' " \;
flolo
fonte
17
O que o OP estava tentando realizar pode ser atendido com as sugestões acima, mas essa é a que realmente responde à pergunta. Existem razões para fazê-lo desta maneira - exec é muito mais poderoso do que apenas operar nos arquivos retornados pelo find, especialmente quando combinado com o teste. Por exemplo: encontre geda-gaf / -type d -exec bash -c 'DIR = {}; [[$ (encontre $ DIR -maxdepth 1 | xargs grep -i especiaria | wc -l) -ge 5]] && echo $ DIR '\; Irá retornar todos os diretórios no caminho de procura que contêm mais de 5 linhas totalizar entre todos os arquivos no diretório contendo a palavra tempero
swarfrat
3
Melhor resposta. Grepping a saída inteira (como sugerem outras respostas) não é o mesmo que grep cada arquivo. Dica: em vez de sh, você pode usar qualquer outro shell que desejar (tentei isso com o bash e está funcionando ok).
Paginuca
1
Certifique-se de não ignorar a -copção. Caso contrário, você receberá uma No such file or directorymensagem de erro intrigante .
Asmaier 6/12/13
aqui está um ótimo substituto do ps que utiliza find com tubulação dentro de um shell exec'd: / usr / bin / find / proc -mindepth 1 -maxdepth 1 -type d -regex '. * / [0-9] +' - print -exec bash -c "cat {} / cmdline | tr '\\ 0' ''; eco" \;
precisa saber é
1
Exemplo de encontrar arquivos e renomeando-os com sed usando expressão regular find -type f -name '*.mdds' -exec sh -c "echo {} | sed -e 's/_[0-9]\+//g' | xargs mv {}" \;
Rostfrei
16
find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'
Paul Tomblin
fonte
Esperando evitar -print e xargs por razões de eficiência. Talvez isso é realmente o meu problema: achado não consegue lidar canalizada comandos através -exec
someguy
Isso não funciona com arquivos com espaços em seus nomes; Para corrigir, substitua -print com -print0 e adicione a opção -0 para xargs
Adam Rosenfield
2
@someguy - O que? Evitar xargs por razões de eficiência? Chamar uma instância do zcat e passar uma lista de vários arquivos é muito mais eficiente do que executar uma nova instância para cada arquivo encontrado.
Sherm Pendley
@ Adam - Eu fiz sua alteração sugerida. 99% do tempo em que estou fazendo descobertas, ele está nos meus diretórios de código-fonte e nenhum dos arquivos tem espaços, por isso não me importo com o print0. Agora, meu diretório de documentos, por outro lado, lembro-me do print0.
Paul Tomblin
10

Você também pode canalizar para um whileloop que pode executar várias ações no arquivo findlocalizado. Então, aqui está um para procurar nos jararquivos um determinado arquivo de classe java na pasta com uma grande distribuição de jararquivos

find /usr/lib/eclipse/plugins -type f -name \*.jar | while read jar; do echo $jar; jar tf $jar | fgrep IObservableList ; done

o ponto principal é que o whileloop contém vários comandos que referenciam o nome do arquivo passado separado por ponto-e-vírgula e esses comandos podem incluir canais. Portanto, nesse exemplo, eu ecoo o nome do arquivo correspondente e listo o que está no filtro de archive para um determinado nome de classe. A saída se parece com:

/usr/lib/eclipse/plugins/org.eclipse.core.contenttype.source_3.4.1.R35x_v20090826-0451.jar /usr/lib/eclipse/plugins/org.eclipse.core.databinding.observable_1.2.0.M20090902-0800 .jar org / eclipse / core / databinding / observable / list / IObservableList .class /usr/lib/eclipse/plugins/org.eclipse.search.source_3.5.1.r351_v20090708-0800.jar / usr / lib / eclipse / plugins / org.eclipse.jdt.apt.core.source_3.3.202.R35x_v20091130-2300.jar /usr/lib/eclipse/plugins/org.eclipse.cvs.source_1.0.400.v201002111343.jar / usr / lib / eclipse / plugins / org.eclipse.help.appserver_3.1.400.v20090429_1800.jar

no meu shell bash (xubuntu10.04 / xfce), ele realmente torna o nome da classe correspondente em negrito, pois fgrepdestaca a string correspondente; isso facilita muito a varredura da lista de centenas de jararquivos pesquisados ​​e a visualização fácil de quaisquer correspondências.

no Windows, você pode fazer o mesmo com:

for /R %j in (*.jar) do @echo %j & @jar tf %j | findstr IObservableList

observe que, no Windows, o separador de comandos é '&' not ';' e que o '@' suprime o eco do comando para fornecer uma saída organizada, assim como o linux encontra a saída acima; apesar de findstrnão tornar a string correspondente em negrito, você deve olhar um pouco mais de perto a saída para ver o nome da classe correspondente. Acontece que o comando 'for' do Windows conhece alguns truques, como percorrer arquivos de texto ...

desfrutar

simbo1905
fonte
2

Eu descobri que a execução de um comando shell de string (sh -c) funciona melhor, por exemplo:

find -name 'file_*' -follow -type f -exec bash -c "zcat \"{}\" | agrep -dEOE 'grep'" \;
Andrew Khoury
fonte
0

Se você está procurando uma alternativa simples, isso pode ser feito usando um loop:

for i in $(find -name 'file_*' -follow -type f);do zcat $i | agrep -dEOE 'grep');done

ou, de forma mais geral e fácil de entender:

for i in $(YOUR_FIND_COMMAND);do YOUR_EXEC_COMMAND_AND_PIPES );done

e substitua qualquer {} por $ i em YOUR_EXEC_COMMAND_AND_PIPES

Louis Gagnon
fonte