Dupla diabólica: find e xargs

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

[ Hits: 34.129 ]

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

Porteus Linux

Tabela sem Table, só com CSS

Instalação de uma HP Deskjet 3535 no Slackware 10.2

Aplicações WEB vulneráveis para testes práticos

Como montar um celular Moto G ou Moto E no CentOS usando MTP

  

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 RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts