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.