find: argumento ausente para -exec

18

Estou tentando executar o seguinte comando:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' +

Isso está retornando um erro:

find: missing argument to -exec

Não vejo o que há de errado com este comando, pois parece corresponder à página de manual:

comando -exec {}

Essa variante da opção -exec executa o comando especificado nos arquivos selecionados, mas a linha de comando é criada anexando cada nome de arquivo selecionado no final; o número total de invocações do comando será muito menor que o número de arquivos correspondentes. A linha de comando é construída da mesma maneira que o xargs cria suas linhas de comando. Somente uma instância de '{}' é permitida dentro do comando. O comando é executado no diretório inicial.

Eu também tentei:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' '{}' +
find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar '{}' +
find a/folder b/folder \( -name *.c -o -name *.h \) -exec grep -I foobar '{}' +
find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+
David Kennedy
fonte
Você já tentou escapar +do final? find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+
Jayhendren #
3
Você pode estar usando uma versão antiga do GNU find. Embora a -exec cmd {} +variante seja POSIX e esteja disponível desde os anos 80, o GNU encontrou apenas a adição (relativamente) recentemente (2005). O que find --versionte diz?
Stéphane Chazelas
2
@ Koveras, seria assim então. -exec {} +foi adicionado em 4.2.12 em 2005. Nos achados mais antigos do GNU, você pode usar o (não POSIX) -print0 | xargs -r0para obter algo semelhante. 4.1é de 1994.
Stéphane Chazelas
1
JRFerguson apontou (em uma resposta que foi excluído) que os -nameargumentos padrão deve ser citado: -name "*.c" -o -name "*.h". Isso é verdade, embora não esteja relacionado ao -execerro. Você notará que todas as outras respostas colocam os curingas entre aspas, embora apenas Gilles o mencione. … (Continua)
G-Man diz 'Restabelecer Monica' em
1
(Continua) ... a resposta do jlliagre recolhe a expressão do nome para -name "*.[ch]"sem explicação. Isso tem os benefícios de simplificar a linha de comando e, especificamente, eliminar o  -o. -oÉ difícil encontrar expressões que envolvam isso. O seu está errado; se o seu comando for corrigido para não causar erros (como na resposta de Gilles), ele será executado grepapenas nos .harquivos. Você precisa fazer '(' -name '*.c' -o -name '*.h' ')'.
G-Man Diz 'Reinstate Monica'

Respostas:

18

Você precisa remover as aspas simples que você usa {}. O comando pode ser simplificado assim:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} +

Se você usa uma versão arcaica do GNU find, isso ainda deve funcionar:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} \;
jlliagre
fonte
Opa, eles foram feitos para serem citações, não backticks.
David Kennedy
As cotações seriam inúteis, pois {}não têm significado específico para o shell.
Jlliagre
Nas páginas do manual find: "A string '{}' é substituída pelo nome do arquivo atual sendo processado em todos os lugares em que ocorre nos argumentos do comando, não apenas nos argumentos em que está sozinho, como em algumas versões do find. as construções podem precisar ser escapadas (com um '\') ou citadas para protegê-las da expansão pelo shell ".
David Kennedy
1
Na verdade, eu li isso na página do manual, mas o fato é que não há shell que eu saiba que exija citação de chaves. Qual shell você está usando?
Jlliagre
bater. Com ou sem as aspas, recebo o erro de qualquer maneira.
David Kennedy
10

"Falta de argumento para -exec" normalmente significa que o argumento para - execestá faltando seu terminador. O terminador deve ser um argumento contendo apenas o caractere ;(que precisa ser citado em um comando shell, portanto, normalmente é escrito \;ou ';') ou dois argumentos sucessivos contendo {}e +.

Stephane Chazelas identificou que você está usando uma versão mais antiga do GNU find, que não suporta -exec … {} +apenas -exec {} \;. Embora o GNU tenha adotado tardiamente -exec … {} +, eu recomendo que você obtenha um conjunto de ferramentas menos antigo (como o Cygwin , que inclui git e muito mais, ou o GNUwin32 , que não possui git, mas não tem a tentativa de mau funcionário -para-usar-linux-mas-nós-impomos-vibe Windows que Cygwin dá). Este recurso foi adicionado na versão 4.2.12, mais de 9 anos atrás (foi o último recurso identificado para tornar o GNU findPOSIX compatível).

Se você deseja manter uma localização antiga do GNU, pode usar -print0com xargs -0para obter uma funcionalidade semelhante: execução de comandos agrupados, suportando nomes de arquivos arbitrários.

find a/folder b/folder -name '*.c' -o -name '*.h' -print0 | xargs -0 grep -I foobar /dev/null

Sempre cite os curingas na findlinha de comando. Caso contrário, se você executar esse comando a partir de um diretório que contém .carquivos, o não citado *.cserá expandido para a lista de .carquivos no diretório atual.

Adicionar /dev/nullà greplinha de comando é um truque para garantir que o grep sempre imprima o nome do arquivo, mesmo que findencontre uma única correspondência. Com o GNU find, outro método é passar a opção -H.

Gilles 'SO- parar de ser mau'
fonte
1
O que você quer dizer com vibração de mau funcionário tentando usar o Linux, mas nós impomos o Windows que o cygwin fornece?
David Kennedy
GnuWin32 não ter de esperar :(
David Kennedy
Veja meus comentários sobre a questão.
G-Man diz 'Reinstate Monica'
As aspas ao redor do semi funcionavam de dentro de um script package.json.
bvj 12/11
2

Se um comando como

find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar {} +

retorna erro

find: missing argument to -exec

a causa provável é o GNU muito antigo, findque não suporta sintaxe -exec mycommand {} +. Nesse caso, é necessário executar uma substituição de baixo desempenho, -exec mycommand {} \;que executará o mycommanddestino único para cada destino encontrado, em vez de coletar vários destinos e executar o mycommandapenas uma vez.

No entanto, o GNU findnão suporta, por exemplo,

find . -type f -and -name "*.ttf" -exec cp {} ~/.fonts +

porque o GNU findsuporta apenas combinações literais em {} +vez de mais genéricas {} additional parameters +. Observe que não pode haver nada entre os aparelhos e o +personagem. Se você tentar isso, receberá o mesmo erro:

find: missing argument to -exec

A solução alternativa é usar a sintaxe {} additional parameters \;que funciona, mas executará o comando uma vez para cada destino encontrado. Se você precisar de mais desempenho com o GNU, findprecisará escrever um script de wrapper que possa acrescentar parâmetros adicionais aos argumentos fornecidos. Algo como

#!/bin/bash
exec mycommand "$@" additional parameters

deve ser bom o suficiente. Ou, se você não deseja criar um arquivo temporário, pode usar uma linha para alterar a ordem dos parâmetros como esta:

find . -type f -and -name "*.ttf" -exec bash -c 'mycommand "$@" extra arguments' {} +

que será executado mycommand {list of ttf files} extra arguments. Observe que pode ser necessário escape duplo de caracteres especiais para o bash após a -cbandeira.

Mikko Rantalainen
fonte
(1) A parte do acima exposto que realmente responde à pergunta já foi dada por outras pessoas. (2) O que você está descrevendo não é uma falha ou deficiência no GNU find, mas o comportamento correto especificado pelo POSIX .
G-Man diz 'Reinstate Monica'
1
+1 Finalmente, alguém que responde por que parâmetros adicionais não funcionam! Parece uma deficiência na definição do POSIX.
Jonathan
Se você possui o GNU, findprovavelmente o possui cp. Nesse caso, você pode find ... -exec cp --target-directory ~/.fonts {} +manter o {}no final da sequência de execução.
roaima
1

find . -type f -perm 0777 -exec chmod 644 {}\;

obteve erro find: missing argument to ``-exec'.

Adicionando espaço entre {}e \corrigido:

find . -type f -perm 0777 -print -exec chmod 644 {} \;

ShreePool
fonte
1
Não existe esse problema no findcomando na pergunta em questão.
Kusalananda
Na questão, não é, tudo bem, que eu entendi, mas o problema é o mesmo "find: falta de argumento para` `-exec '". O problema pode ocorrer por uma razão diferente de 2, respondi porque vi a mesma declaração de problema.
ShreePool 20/03
@Kusalananda, luto, o noob forneceu uma solução para o erro relatado, que é declarado pelo OP no título e no corpo da pergunta.
bvj 27/04
@bvj A questão lida explicitamente com a +forma da -execopção find. Esta resposta está corrigindo um problema que o usuário que está fazendo a pergunta não possui.
Kusalananda
-1

Eu tive minha parcela de dores de cabeça com a sintaxe exec no passado. Na maioria dos dias, agora prefiro a sintaxe mais agradável do bash:

for f in `find a/folder b/folder -name "*.[ch]"`; do grep -I foobar $f; done

Existem algumas limitações quando você deseja tratar os arquivos como um grupo, pois cada um é avaliado em série, mas você pode canalizar a saída para outro local muito bem

tolster710
fonte
1
Enquanto isso tende a funcionar, é significativamente menos útil que a versão de busca pura, porque não pode manipular arquivos com espaço em branco no nome corretamente.
Etan Reisner
5
Não faça isso. Isso é interrompido assim que os arquivos contêm espaços e outros caracteres "estranhos". Isso também é mais complexo e mais lento do que find … -exec … \;, portanto, não há razão para usá-lo, mesmo que você saiba que seus nomes de arquivo são mansos.
Gilles 'SO- stop be evil'
isso foi útil para minha situação em que eu precisava executar várias linhas de lógica com base nos nomes dos arquivos (como remover caracteres, criar diretórios e depois mover os arquivos). Tentar encontrar várias coisas em uma só execfoi uma dor de cabeça durante os 5 minutos que eu queria gastar nisso. Meus nomes de arquivo eram mansos e isso resolveu meu problema :)
gMale