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:
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. :]
[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
[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
[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.