Domine o `xargs` no Linux: Potencialize seus comandos!

Se você precisa executar uma série de comandos no Linux, mas se depara com um que não aceita entrada via pipeline, o `xargs` surge como uma solução eficaz. Este utilitário habilita a transformação da saída de um comando, convertendo-a em argumentos para outro.

Em sistemas Linux, cada utilitário padrão opera com três fluxos de dados: entrada padrão (stdin), saída padrão (stdout) e erro padrão (stderr). Todos esses fluxos funcionam com texto. A entrada (stdin) é enviada a um comando via texto, e a resposta (stdout) é apresentada no terminal, também como texto. Da mesma forma, mensagens de erro (stderr) são exibidas no terminal.

Uma das características notáveis do Linux e sistemas semelhantes é a capacidade de direcionar a saída (stdout) de um comando para a entrada (stdin) de outro. Isso permite que o primeiro comando não dependa de uma saída no terminal, e o segundo não se preocupe se sua entrada vem do teclado.

Embora todos os comandos no Linux possuam os três fluxos padrão, nem todos aceitam a saída de um comando como entrada para seu stdin, o que limita a possibilidade de enviar dados para eles. É aí que o `xargs` se torna indispensável.

O `xargs` é uma ferramenta para construir pipelines de execução usando os fluxos de dados padrão. Com ele, comandos como `echo`, `rm` e `mkdir` podem aceitar entradas padrão como argumentos, expandindo seu uso e flexibilidade.

Como Funciona o Comando xargs?

O `xargs` aceita entradas via pipeline ou de um arquivo. Ele usa essa entrada como parâmetros para os comandos especificados. Se nenhum comando for indicado, `xargs` utilizará o `echo` por padrão. Uma característica notável do `xargs` é que ele sempre produzirá uma única linha de saída, mesmo quando processa entradas de várias linhas.

Vamos demonstrar isso. Usando a opção `-1` (listar um arquivo por linha) com `ls`, obtemos uma coluna única de nomes de arquivos:

ls -1 ./*.sh

Este comando listará todos os arquivos de script shell no diretório atual.

O resultado é uma coluna única de nomes. Agora, ao canalizar essa saída para `xargs`:

ls -1 ./*.sh | xargs

A saída é apresentada como um longo fluxo de texto na janela do terminal.

Essa característica permite que `xargs` alimente parâmetros em outros comandos.

Exemplos Práticos de Uso do xargs

Contando Palavras com wc

Podemos usar `xargs` para contar facilmente palavras, caracteres e linhas em vários arquivos:

ls *.page | xargs wc

Neste caso:

  • `ls` lista os arquivos com a extensão `.page` e envia essa lista para `xargs`.
  • `xargs` repassa os nomes dos arquivos para o comando `wc`.
  • `wc` processa os nomes dos arquivos como se fossem argumentos passados na linha de comando.

As estatísticas de cada arquivo são exibidas, juntamente com um total geral.

Utilizando Confirmação com xargs

A opção `-p` (interativo) permite que o `xargs` solicite sua confirmação antes de executar o comando. Por exemplo:

echo 'one two three' | xargs -p touch

O comando a ser executado é exibido, e o `xargs` aguarda uma resposta: `y` (sim), `Y` (sim), `n` (não) ou `N` (não), seguido de Enter. Se apenas Enter for pressionado, o comando será tratado como “não”.

Ao digitar “y” e pressionar Enter, os arquivos são criados. Podemos usar `ls` para verificar:

ls one two three

Múltiplos Comandos com xargs

A opção `-I` (argumentos iniciais) permite utilizar múltiplos comandos com `xargs`. Esta opção define uma “string de substituição”, onde os valores fornecidos ao `xargs` são inseridos sempre que o token para a string de substituição aparece na linha de comando. Vamos usar o comando `tree` para ver os subdiretórios do diretório atual:

tree -d

Suponha que tenhamos um arquivo chamado “directories.txt” contendo nomes de diretórios que desejamos criar. Podemos ver o conteúdo deste arquivo usando `cat`:

cat directories.txt

Utilizaremos este arquivo como entrada para `xargs`:

cat directories.txt | xargs -I % sh -c 'echo %; mkdir %'

Este comando opera da seguinte forma:

  • `cat directory.txt |`: Envia o conteúdo de “directories.txt” para `xargs`.
  • `xargs -I%`: Define “%” como a “string de substituição”.
  • `sh -c`: Inicia um novo subshell, onde o `-c` indica que os comandos serão lidos da linha de comando.
  • `’echo %; mkdir %’`: Os tokens “%” são substituídos pelos nomes de diretório. O comando `echo` imprime o nome do diretório e o comando `mkdir` o cria.

Os diretórios são listados um a um e criados.

Podemos confirmar a criação dos diretórios usando `tree`:

tree -d

Copiando Arquivos para Múltiplos Locais

Podemos usar o `xargs` para copiar arquivos para vários locais com um único comando. Vamos canalizar dois diretórios como entrada para `xargs` e usar a opção `-n` (número máximo) com valor 1 para que ele processe um parâmetro por vez:

echo ~/Backups/ ~/Documents/page-files/ | xargs -n 1 cp -v ./*.page

Os arquivos serão copiados para os dois diretórios, um de cada vez. O uso da opção `-v` (verbose) com `cp` permite visualizar o progresso da cópia.

Excluindo Arquivos com Nomes Complexos

Quando os nomes de arquivos contêm espaços ou caracteres estranhos, o `xargs` pode ter dificuldades. Para isso, a opção `-0` (terminador nulo) é ideal, pois usa o caractere nulo como delimitador final para nomes de arquivos. O comando `find` possui uma opção equivalente para isso: `-print0`.

find . -name "*.png" -type f -print0 | xargs -0 rm -v -rf "{}"

Esta linha de comando:

  • `find . -name “*.png” -type f`: Pesquisa arquivos com a extensão `.png` no diretório atual.
  • `-print0`: Delimita os nomes dos arquivos com um caractere nulo, tratando espaços e caracteres especiais corretamente.
  • `xargs -0`: Processa os nomes de arquivos terminados com nulo, evitando problemas com nomes complexos.
  • `rm -v -rf “{}”`: Exclui os arquivos encontrados recursivamente (`-r`), sem confirmação (`-f`), e de forma verbosa (`-v`). O “{}” é substituído por cada nome de arquivo.

Todos os subdiretórios são pesquisados e os arquivos correspondentes ao padrão são excluídos.

Removendo Diretórios Aninhados

Para remover um conjunto de subdiretórios aninhados, podemos usar o seguinte comando:

tree -d

find . -name "level_one" -type d -print0 | xargs -0 rm -v -rf "{}"

Este comando utiliza `find` para pesquisar recursivamente diretórios chamados “level_one”. Os nomes dos diretórios encontrados são enviados para `rm` via `xargs`. A principal diferença deste comando para o exemplo anterior é que `-type d` especifica que estamos buscando por diretórios, não por arquivos.

Os nomes dos diretórios são impressos à medida que são excluídos.

Podemos confirmar que os diretórios foram excluídos com `tree`:

tree -d

Excluindo Todos os Arquivos, Exceto um Tipo

Para excluir todos os arquivos, exceto um tipo específico, podemos usar a opção `-not` com `find`. No exemplo abaixo, estamos retendo apenas os arquivos com extensão `.sh`:

find . -type f -not -name "*.sh" -print0 | xargs -0 -I {} rm -v {}

Podemos verificar a lista de arquivos restantes com `ls`:

ls -l

Criando um Arquivo Compactado com Xargs

Podemos usar `find` e `xargs` para criar um arquivo compactado com `tar`. Por exemplo, para compactar arquivos com extensão `.page`:

find ./ -name "*.page" -type f -print0 | xargs -0 tar -cvzf page_files.tar.gz

À medida que o arquivo compactado é criado, os arquivos são listados.

O xargs: Um Elo Crucial

O `xargs` serve como uma ponte entre comandos que produzem dados e aqueles que não foram projetados para recebê-los diretamente. Dominar o uso do `xargs` aumenta significativamente a sua capacidade de processar dados no Linux.

Tanto o `xargs` quanto o `find` oferecem diversas opções e recursos, portanto, é recomendado consultar as páginas de manual para um conhecimento mais profundo.