Encontro-me constantemente procurando a sintaxe de
find . -name "FILENAME" -exec rm {} \;
principalmente porque não vejo exatamente como a -exec
peça funciona. Qual é o significado das chaves, da barra invertida e do ponto e vírgula? Existem outros casos de uso para essa sintaxe?
man
página antiga do POSIX lê Um nome ou argumento de utilitário que contém apenas os dois caracteres "{}" deve ser substituído pelo nome do caminho atual , que me parece suficiente. Além disso, tem um exemplo com-exec rm {} \;
, assim como na sua pergunta. Nos meus dias, quase não havia outros recursos além da "grande parede cinza", livros deman
páginas impressas (o papel era mais grosso que o armazenamento). Então eu sei que isso é suficiente para alguém novo no tópico. Sua última pergunta, porém, é justa para perguntar aqui. Infelizmente, nem o @Kusalananda nem eu temos uma resposta para isso.xargs
às vezes seja útil,find
pode passar vários argumentos de caminho para comandar sem ele.-exec command... {} +
(com em+
vez de\;
) passa tantos caminhos depoiscommand...
quanto o necessário (cada sistema operacional tem seu próprio limite de quanto tempo uma linha de comando pode ter). E comoxargs
, a+
forma terminadas em defind
's-exec
ação também será executadocommand...
várias vezes no caso raro que há muitos caminhos para caber dentro do limite.Respostas:
Esta resposta vem nas seguintes partes:
-exec
-exec
em combinação comsh -c
-exec ... {} +
-execdir
Uso básico de
-exec
A
-exec
opção pega um utilitário externo com argumentos opcionais como argumento e o executa.Se a string
{}
estiver presente em qualquer lugar do comando, cada instância será substituída pelo nome do caminho atualmente sendo processado (por exemplo./some/path/FILENAME
). Na maioria dos shells, os dois caracteres{}
não precisam ser citados.O comando precisa ser finalizado com um
;
parafind
saber onde termina (pois pode haver outras opções posteriormente). Para proteger o;
shell, ele precisa ser citado como\;
ou';'
, caso contrário, o shell o verá como o final dofind
comando.Exemplo (
\
no final das duas primeiras linhas são apenas para continuações de linha):Ele encontrará todos os arquivos regulares (
-type f
) cujos nomes correspondem ao padrão*.txt
no diretório atual ou abaixo dele. Ele testará se a sequênciahello
ocorre em qualquer um dos arquivos encontrados usandogrep -q
(o que não produz nenhuma saída, apenas um status de saída). Para os arquivos que contêm a string,cat
será executado para enviar o conteúdo do arquivo para o terminal.Cada um
-exec
também age como um "teste" nos nomes de caminhos encontrados porfind
, exatamente como-type
e-name
faz. Se o comando retornar um status de saída zero (significando "sucesso"), a próxima parte dofind
comando será considerada, caso contrário, ofind
comando continuará com o próximo nome do caminho. Isso é usado no exemplo acima para encontrar arquivos que contêm a sequênciahello
, mas para ignorar todos os outros arquivos.O exemplo acima ilustra os dois casos de uso mais comuns de
-exec
:find
comando).Usando
-exec
em combinação comsh -c
O comando que
-exec
pode ser executado é limitado a um utilitário externo com argumentos opcionais.-exec
Não é possível usar embutidos, funções, condicionais, pipelines, redirecionamentos etc. diretamente dosh -c
shell , a menos que seja envolto em algo como um shell filho.Se
bash
forem necessários recursos, usebash -c
no lugar desh -c
.sh -c
é executado/bin/sh
com um script fornecido na linha de comando, seguido por argumentos opcionais da linha de comando para esse script.Um exemplo simples de uso
sh -c
por si só, semfind
:Isso passa dois argumentos para o script do shell filho:
A cadeia
sh
. Isso estará disponível como$0
dentro do script e, se o shell interno emitir uma mensagem de erro, ele será prefixado com essa sequência.O argumento
apples
está disponível como$1
no script, e se houvesse mais argumentos, eles estariam disponíveis como$2
,$3
etc. Eles também estariam disponíveis na lista"$@"
(exceto pelos$0
quais não faria parte"$@"
).Isso é útil em combinação com
-exec
, pois permite criar scripts arbitrariamente complexos que atuam nos nomes de caminho encontrados porfind
.Exemplo: encontre todos os arquivos regulares que possuem um determinado sufixo de nome de arquivo e altere esse sufixo para outro sufixo, onde os sufixos são mantidos nas variáveis:
Dentro do script interno,
$1
seria a stringtext
,$2
seria a stringtxt
e$3
seria o nome do caminhofind
encontrado para nós. A expansão do parâmetro${3%.$1}
pegaria o nome do caminho e removeria o sufixo.text
dele.Ou, usando
dirname
/basename
:ou, com variáveis adicionadas no script interno:
Observe que nesta última variação, as variáveis
from
eto
no shell filho são distintas das variáveis com os mesmos nomes no script externo.A descrição acima é a maneira correta de chamar um script complexo arbitrário de
-exec
withfind
. Usandofind
em um loop comoé propenso a erros e deselegante (opinião pessoal). Ele está dividindo nomes de arquivos em espaços em branco, invocando o globbing do nome de arquivo e também força o shell a expandir o resultado completo
find
antes mesmo de executar a primeira iteração do loop.Veja também:
Usando
-exec ... {} +
O
;
no final pode ser substituído por+
. Isso fazfind
com que o comando fornecido seja executado com o maior número possível de argumentos (nomes de caminhos encontrados), em vez de uma vez para cada nome de caminho encontrado. A string{}
deve ocorrer imediatamente antes do+
para que isso funcione .Aqui,
find
você coletará os nomes de caminho resultantes e executará ocat
maior número possível de uma vez.Da mesma forma aqui,
mv
será executado o menor número de vezes possível. Este último exemplo requer o GNUmv
do coreutils (que suporta a-t
opção).O uso
-exec sh -c ... {} +
também é uma maneira eficiente de fazer um loop sobre um conjunto de nomes de caminho com um script arbitrariamente complexo.O básico é o mesmo que quando usado
-exec sh -c ... {} ';'
, mas o script agora leva uma lista muito maior de argumentos. Eles podem ser repetidos repetidamente"$@"
dentro do script.Nosso exemplo da última seção que altera os sufixos do nome do arquivo:
Usando
-execdir
Também existe
-execdir
(implementado pela maioria dasfind
variantes, mas não uma opção padrão).Isso funciona
-exec
com a diferença de que o comando shell fornecido é executado com o diretório do nome do caminho encontrado como seu diretório de trabalho atual e que{}
conterá o nome de base do nome de caminho encontrado sem o caminho (mas o GNUfind
ainda prefixará o nome de base com./
BSDfind
não fará isso).Exemplo:
Isso moverá cada arquivo encontrado
*.txt
para umdone-texts
subdiretório pré-existente no mesmo diretório em que o arquivo foi encontrado . O arquivo também será renomeado adicionando o sufixo.done
a ele.Isso seria um pouco mais complicado
-exec
, já que precisaríamos obter o nome de base do arquivo encontrado{}
para formar o novo nome do arquivo. Também precisamos do nome do diretório de{}
para localizar odone-texts
diretório corretamente.Com
-execdir
, algumas coisas como essas se tornam mais fáceis.A operação correspondente usando em
-exec
vez de-execdir
teria que empregar um shell filho:ou,
fonte
-exec
pega um programa e argumentos e o executa; alguns comandos do shell consistem apenas em um programa e argumentos, mas muitos não. Um comando shell pode incluir redirecionamento e tubulação;-exec
não pode (embora o todofind
possa ser redirecionado). Um comando shell pode usar; && if
etc;-exec
não pode, embora-a -o
possa fazer algumas. Um comando shell pode ser um alias ou função shell, ou embutido;-exec
não podes. Um comando shell pode expandir vars;-exec
não pode (embora o shell externo que executa afind
lata). Um comando shell pode substituir de maneira$(command)
diferente a cada vez;-exec
não podes. ...-exec
não pode - emborafind
possa iterar sobre arquivos da mesma forma que a maioria dos globs, então isso raramente é desejado.sh
em si, que é totalmente competentemente de fazer todas essas coisasfind -exec cmd arg \;
não invoca um shell para interpretar uma linha de comando do shell, ele é executadoexeclp("cmd", "arg")
diretamente, nãoexeclp("sh", "-c", "cmd arg")
(para o qual o shell acabaria fazendo o equivalente aexeclp("cmd", "arg")
secmd
não estivesse embutido).find
argumentos após-exec
e até;
ou+
compõem o comando para executar junto com seus argumentos, com cada instância de um{}
argumento substituída pelo arquivo atual (com;
) e{}
como o último argumento antes+
substituído por uma lista de arquivos como argumentos separados (no{} +
caso). O IOW-exec
recebe vários argumentos, finalizados por um;
ou{}
+
.