xargs: A ponte entre entrada padrão e a lista de parâmetros

Update: Apenas mudança na formatação. Texto justificado. Mudança no formato das figuras (jpg)

O xargs é um programa de linha de comando que transforma o conteúdo de sua entrada padrão na lista de parâmetros de um segundo comando, à sua escolha. Muito útil quando você tem um texto qualquer e, com cada parte desse texto, deseja executar um comando. Um exemplo clássico é o redimensionamento de uma quantidade muito grande imagens, ou a necessidade de baixar da rede uma lista de arquivos.

Tudo bem que o segundo exemplo é facilmente resolvido com um simples wget -i, mas podemos também usar o xargs!

Como entender é muito mais fácil com exemplo, vamos a eles!

Imagina a situação onde você possui uma pasta com ~400 fotos, recém descarregadas da sua super máquina digital de 7.1MP. Cada foto ocupa lá seus 4MBytes e obviamente você não vai enviar por email ou fazer upload para seu album digital mandando cada foto com seu tamanho original!

Então precisamos reduzir o tamanho (tanto dimensão quanto tamanho em bytes) de cada arquivo descarregado. Temos duas opções:

  • Alterar arquivo por arquivo. Ou abrindo cada um deles em um editor de imagens ou rodando a mesma linha de comento ~400 vezes;
  • Usar o xargs de alguma forma para nos ajudar nessa tarefa que deveria ser chata mas não será! =)

Usando o xargs

Antes de realmente usar o xargs é bom dar uma lida em seu manual (man xargs) para conhecer melhos suas opções. Aqui usaremos apenas algumas de suas muitas opções de linha de comando.

Supondo que os arquivos estão na pasta fotos, um simples ls nos mostra o que temos em mãos.

ls mostrando as fotos em nosso diretório de exemplo

ls mostrando as fotos em nosso diretório de exemplo

Ok, ok, não temos as 400 imagens mas imagine que temos! =)

Bom, agora precisamos reduzir o tamanho de cada uma de nossas imagens. O xargs sempre funciona em conjunto com um segundo comando, esse segundo comando é quem realmente vai fazer o trabalho de redimensionar as imagens. O xargs, como o próprio título diz, é apenas a ponte.

Para dimensinar uma imagem usaremos o comando convert. A sintaxe que usaremo será:

convert -resize 1024×768 <arquivo-de-origem> <arquivo-de-destino>

Isso criará um novo arquivo (<arquivo-de-destino>) que será uma nova imagem, igual à imagem original, porém reduzida.

Começamos o trabalho produzindo a lista de arquivos que queremos transformar. Essa lista é o nosso texto, citado na introdução do post. Para isso, fazemos um ls -1, que nos retorna apenas o nome dos arquivos, um por linha.

Saída do comando ls mostrando os nomes dos arquivos, um por linha

Saída do comando ls mostrando os nomes dos arquivos, um por linha

Pronto. Agora precisamos repassar essa lista para o xargs para que ele possa repassá-la para o convert, item a item, para que o convert possa fazer seu trabalho. Lembrando que geralmente a cada item repassado pelo xargs esse item é inserido no final da lista de parametros de nosso comando escolhido. Então fazemos:

ls -1 *.JPG | xargs -n1 -iarquivo convert -resize 1024×768 arquivo thumbs/arquivo

  • O parâmetro -n1 faz com que o xargs passe um item de cada vez para nosso comando escolhido.
  • O parametro -iarquivo faz com que qualquer ocorrência da string “arquivo” seja substituída pelo item que está sendo repassado. Usamos essa opção para poder inserir cada item repassado no meio da linha de comando que será executada.
  • Todos os outros parâmetros formam a linha de comando que será executada pelo xargs, a cada iteração! Esses outros parâmetros são: convert -resize 1024×768 arquivo thumbs/arquivo.

Para conferir o que será feito, podemos inserir o comando echo antes do comando convert. Assim o xargs executará o comando echo e isso fará com que apenas o resultado final (montado pelo xargs) seja impresso no terminal, e nenhuma conversão deimagem seja de fato executada.

Prévia do que será realmente executado quando retirarmos o "echo".

Prévia do que será realmente executado quando retirarmos o "echo".

Vejam o que foi impresso. Exatamente e lista de todos os comando que precisamos para converter cada uma das imagens! Agora temos duas formas de efetivar essas mudanças (o redimensionamento em si).

  • Retiramos o comando echo e deixamos que o xargs execute diretamente o convert
  • Repassamos todo o conteúdo impresso para o /bin/bash para que ele execute!

Não entendeu a segunda opção? Eu explico! Se pararmos pra pensar, o que está impresso em nosso terminal é um script shell, certo? Certo!

E quem nós sabemos que é especializado em executar scripts shell? Bash! Ainda não entendeu? Então…. Imagina que o conteúdo impresso aí no terminal fosse salvo em um arquivo chamado redimensiona-fotos.sh. Quando chamássemos ./redimensiona-fotos.sh todos aqueles comandos não seriam executados em sequência, como todo bom shell script?? Pois é, o que estamos fazendo é exatamente isso mas com uma diferença sutil, não estamos criando arquivo nenhum! Estamos passando tudo diretamente da saída de um comando (xargs + echo) para a entrada de outro (bash).

Para fazer a segunda opção, basta rodar o mesmo comando acrescido de | /bin/bash –. Então temos:

ls -1 *.JPG | xargs -n1 -iarquivo convert -resize 1024×768 arquivo thumbs/arquivo | /bin/bash –

Essa última parte faz com que o bash execute o conteúdo de sua entrada padrão, em vez de tentar ler um arquivo para executá-lo.

Depois de rodar esse linha, temos em nossa pasta fotos/thumbs, uma cópia de cada arquivo contendo sua imagem original redimensionada!

Execução final do comando

Execução final do comando

Claro que, antes de rodá-lo, precisamos criar a pasta thumbs com um mkdir thumbs. =)

Upadate #1: 26/04/2009

Cuidado com os arquivos com espaços no nome

Apesar de não gostar e não aconselhar espaços em nomes de arquivo, muitas vezes nos deparamos com essa situação. Já percebi, empiricamente, que o espaço não é bem um amigo dos nomes de arquivos, já que é esse o caractere usado para separar os parâmetros de uma chamada a um comando qualquer. Sempre que estamos em um terminal e precisamos usar um arquivo com espaço no nome temos que fazer o famoso escape, usando a barra invertida. Quando você tem arquivos com espaço no nome a dica acima não funciona de primeira, precisamos passar mais um parâmetro par o xargs que é o -0 (menos zero). Segue um exemplo:

ls-com-espaco

Esse é um exemplo de uma pasta onde temos arquivos que possuem espaço no nome. Se usarmos o xargs junto com echo podemos ver que o resultado não é o que queremos, veja:

xargs-que-nao-da-certo

Pela imagem podemos perceber que os arquivos com espaço no nome foram quebrados e repassados como itens diferentes ao comando echo. Por exempo, em vez de o comando echo receber o item foto legal.jpg ele recebeu dois itens: foto e legal.jpg, que obviamente, não é o que queremos. Para resolver isso, passamos o parâmetro -0 que faz o xargs usar o \n (fim de linha) como o separador de itens, assim:

xargs-com-fim-de-linha-como-separador

Agora sim, temos o itens repassados de forma correta!

, , ,

  1. #1 por Igor em 21/04/2009 - 23:39

    Muito legal! Vc me fez lembrar como a tela preta é poderosa! :- )

    Abraços e parabéns pelo blog!

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: