Dupla diabólica: find e xargs

Publicado por Jivago J. Alves em 07/07/2008

[ Hits: 27.519 ]

Blog: http://jivagoalves.blogspot.com

 


Dupla diabólica: find e xargs



Hoje veremos uma dupla considerada diabólica no shell, se utilizada sem a devida atenção: o find e o xargs.

O find, como o nome diz, é utilizado para se encontrar arquivos no sistema. Já o xargs facilita a repetição de um certo comando para cada entrada fornecida para ele. Peraí, vamos entender melhor. Considere que eu queira apagar os arquivos terminados em ~ no diretório atual. Poderíamos utilizar a dupla da seguinte maneira:

$ find . -name "*~" | xargs rm

Aqui o find retornaria uma saída com os arquivos terminados em ~ e o xargs executaria o comando rm para cada uma das saídas.

Por exemplo, crie um diretório teste e entre nele:

$ mkdir teste; cd teste

Agora crie os arquivos "teste" e "teste~":

$ > teste; > teste~
$ ls

teste teste~

Agora vamos apagar os arquivos terminados em ~ do diretório atual:

$ find . -name "*~" | xargs rm
$ ls

teste

Olha aí o resultado acima, deu certo.

Até aí tudo bem, mas se o arquivos terminados em ~ possuíssem caracteres em branco? Experimente e crie um "teste 1~". Proteja-o com aspas para que o shell não interprete mal o que queremos:

$ > "teste 1~"
$ ls

teste teste 1~

Agora experimente apagá-lo com:

$ find . -name "*~" | xargs rm
rm: impossível remover `1~': Arquivo ou diretório inexistente

$ ls
teste 1~


E agora, José? Cadê meu arquivo "teste"? Ele APAGOU O ARQUIVO ERRADO!

Isso aconteceu simplesmente porque o rm tratou o arquivo "teste 1~" como dois arquivos diferentes: um "teste" e outro "1~". Ou seja, o espaço em branco acabou com nossa alegria (e talvez o emprego)!

Mas não se apavore, pois uma solução pra isso é utilizar a opção -print0 do find junto com a opção -0 do xargs.

$ > teste
$ ls

teste teste 1~

$ find . -name "*~" -print0 | xargs -0 rm
$ ls

teste

Pronto, agora sim, funcionou! A explicação é que o find separou os arquivos com um caractere nulo. O xargs interpretou os caracteres nulos como separadores dos arquivos e fez o que queríamos. :]

Para mais informações:

$ man find
$ man xargs


Referências:
Outras dicas deste autor

Instalando o Pidgin no Debian

Leitura recomendada

Samba como controlador de domínio + PDC

Synergy-Plus - Controle 2 computadores ou mais com 1 teclado + mouse

Chaves GPG - NO_PUBKEY 85A3D26506C4AE2A

Script pessoal para uso em firmware de access point para conexão automática de PPPOE

Introdução ao QT

  

Comentários
[1] Comentário enviado por maran em 07/07/2008 - 17:00h

ótima dica, parábens.

[2] Comentário enviado por dibetao em 23/08/2011 - 11:51h

gostei!!

[3] Comentário enviado por andersonvom em 23/08/2011 - 12:06h

Excelente dica!
Uma outra solucao é remover os arquivos diretamente com o find:

$ > teste ; > "teste 1~"
$ ls
teste teste 1~
$ find . -name '*~' -exec rm -rf {} \;
$ ls
teste
$

[4] Comentário enviado por rodrigo.a.sc em 19/04/2012 - 20:14h

Tenho uma duvida!
Eu gostaria de fazer o seguintem pegar toda a saida do find, enviar para um arquivo, depois de envfiar para um arquivo eu quero remover todos os arquivos que o caminho esta setado.

Exemplo :

root@FW-01:/home/usr01/teste# > teste
root@FW-01:/home/usr01/teste# >~teste
root@FW-01:/home/usr01/teste# ls
teste ~teste
root@FW-01:/home/usr01/teste# find . -name '*teste' > /home/usr01/teste/dados
root@FW-01:/home/usr01/teste#
root@FW-01:/home/usr01/teste# cat dados
./teste
./~teste
root@FW-01:/home/usr01/teste#

Neste caso eu gostaria de remover : ./teste e ./~teste

Tem como?



[5] Comentário enviado por jivagoalves em 24/04/2012 - 19:46h

@rodrigo.a.sc

Pelo que entendi, você gostaria de remover os arquivos listados dentro do arquivo 'dados'. Sendo assim, você pode enviar os arquivos via pipe do 'cat' pro 'xargs':
$ cat /home/usr01/teste/dados -print0 | xargs -0 rm

Espero ter sido útil!

[6] Comentário enviado por alelima77 em 02/12/2012 - 03:59h

Olá Jivagoalves!
Gostei muito de sa dica. Eu fiz o teste com a dúvida do rodrigo.a.asc e o comando cat que vc passou no final retorna erro, gostaria de saber qual o correto.
Abs!

[7] Comentário enviado por jivagoalves em 02/12/2012 - 11:33h

@alelima77

Desculpe pelo equívoco. Acho que acabei escrevendo rápido sem pensar. Creio que o cat não aceita -print0 como opção. Uma forma de fazer isso é dar como entrada o arquivo dados para o xargs e avisá-lo que o delimitador é uma quebra de linha '\n'. Então ficaria mais ou menos assim:

< /home/usr01/teste/dados xargs -d"\n" rm

Outro exemplo passo-a-passo:

$ ls -l
total 4
-rw-rw-r--. 1 jivago jivago 20 Dec 2 10:28 dados.txt
-rw-rw-r--. 1 jivago jivago 0 Dec 2 10:28 relatorio atual.txt

$ cat dados.txt
relatorio atual.txt

$ < dados.txt xargs ls
ls: cannot access relatorio: No such file or directory
ls: cannot access atual.txt: No such file or directory

$ < dados.txt xargs -d"\n" ls
relatorio atual.txt

Espero que tenha ajudado. Qualquer coisa, só perguntar.

[8] Comentário enviado por Mateus_alves em 23/10/2015 - 03:07h

Excelente post! Simples, didático e prático.

Outra opção para o "e agora, José?" seria:

$ find -name "*~" | xargs -d "\n" rm

Isso porque, -d "/n" orienta o xargs a ignorar os espaços.



Contribuir com comentário




Patrocínio

Site hospedado pelo provedor HostGator.
Linux banner
Linux banner
Linux banner

Destaques

Artigos

Dicas

Viva o Android

Tópicos

Top 10 do mês

Scripts