De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.
Colaboração: Julio Cezar Neves
Data de Publicação: 16 de junho de 2020
Existe um comando, cuja função primordial é construir listas
de parâmetros e passá-la para a execução de outros programas
ou instruções. Este comando é o xargs
e deve ser usado da
seguinte maneira:
xargs [comando [argumento inicial]]
Caso o comando, que pode ser inclusive um script Shell, seja
omitido, será usado por default o echo
.
O xargs
combina o argumento inicial com os argumentos recebidos
da entrada padrão, de forma a executar o comando especificado
uma ou mais vezes.
Exemplo:
Vamos produrar em todos os arquivos abaixo de um determinado
diretório uma cadeia de caracteres usando o comando find
com
a opção -type f
para pesquisar somente os arquivos normais,
desprezando diretórios, arquivos especiais, arquivos de
ligações, etc, e vamos torná-la mais genérica recebendo o
nome do diretório inicial e a cadeia a ser pesquisada como
parâmetros. Para isso fazemos:
$ cat grepr
#
# Grep recursivo
# Pesquisa a cadeia de caracteres definida em $2 a partir do diretorio $1
#
find $1 -type f -print|xargs grep -l "$2"
Na execução deste script procuramos, a partir do diretório
definido na variável $1
, todos os arquivos que continham a
cadeia definida na variável $2
.
Exatamente a mesma coisa poderia ser feita se a linha do programa fosse a seguinte:
find $1 -type f -exec grep -l "$2" {} \;
Este processo tem duas grandes desvantagens sobre o anterior:
grep
será feito em cada arquivo que
lhe for passado pelo find
, um-a-um, ao passo que com o xargs
, será
passada toda, ou na pior das hipóteses, a maior parte possível, da lista de
arquivos gerada pelo find
;
find
,
poderemos ganhar aquela famosa e fatídica mensagem de erro "Too many arguments"
indicando um estouro da pilha de execução do grep
. Como foi
dito no item anterior, se usarmos o xargs
ele passará para o grep
a maior quantidade de parâmetros possível, suficiente para não causar este
erro, e caso necessário executará o grep
mais de uma vez.
ATENÇÃO! Aê pessoal do linux que usa o ls
colorido que nem porta de
tinturaria: nos exemplos a seguir que envolvem esta instrução, vocês devem
usar a opção --color=none
, se não existem grandes chances dos resultados
não ocorrerem como o esperado.
Vamos agora analisar um exemplo que é mais ou menos o inverso deste que acabamos de ver. Desta vez, vamos fazer um script para remover todos os arquivos do diretório corrente, pertencentes a um determinado usuário.
A primeira idéia que surge é, como no caso anterior, usar um comando find
,
da seguinte maneira:
$ find . -user cara -exec rm -f {} \;
Quase estaria certo, o problema é que desta forma você removeria não só os arquivos do cara no diretório corrente, mas também de todos os outros subdiretórios "pendurados" neste. Vejamos então como fazer:
$ ls -l | grep " cara " | cut -c55- | xargs rm
Desta forma, o grep
selecionou os arquivos que continham a cadeia cara
no diretório corrente listado pelo ls -l
. O comando cut
pegou somente
o nome dos arquivos, passando-os para a remoção pelo rm
usando o comando
xargs
como ponte.
O xargs
é também uma excelente ferramenta de criação de
one-liners (scripts de somente uma linha). Veja este para
listar todos os donos de arquivos (inclusive seus links)
"pendurados" no diretório /bin
e seus subdiretórios.
$ find /bin -type f -follow | \ xargs ls -al | tr -s ' ' | cut -f3 -d' ' | sort -u
Muitas vezes o /bin
é um link (se não me engano, no Solaris o
é) e a opção -follows
obriga o find
a seguir o link. O comando
xargs
alimenta o ls -al
e a seqüência de comandos seguinte é
para pegar somente o 3º campo (dono) e classificá-lo devolvendo
somente uma vez cada dono (opção -u
do comando sort
).
Você pode usar as opções do xargs
para construir comandos
extremamente poderosos. Para exemplificar isso e começar a
entender as principais opções desta instrução, vamos supor
que temos que remover todos as arquivos com extensão .txt
sob
o diretório corrente e apresentar os seus nomes na tela. Veja
o que podemos fazer:
$ find . -type f -name "*.txt" | \ xargs -i bash -c "echo removendo {}; rm {}"
A opção -i
do xargs
troca pares de chaves ({}
) pela cadeia
que está recebendo pelo pipe (|
). Então neste caso as chaves
({}
) serão trocadas pelos nomes dos arquivos que satifaçam ao
comando find
.
Olha só a brincadeira que vamos fazer com o xargs
:
$ ls | xargs echo > arq.ls $ cat arq.ls arq.ls arq1 arq2 arq3 $ cat arq.ls | xargs -n1 arq.ls arq1 arq2 arq3
Quando mandamos a saída do ls
para o arquivo usando o xargs
,
comprovamos o que foi dito anteriormente, isto é, o xargs
manda
tudo que é possível (o suficiente para não gerar um estouro
de pilha) de uma só vez. Em seguida, usamos a opção -n 1
para
listar um por vez. Só para dar certeza veja o exemplo a seguir,
quando listaremos dois em cada linha:
$ cat arq.ls | xargs -n 2
arq.ls arq1
arq2 arq3
Mas a linha acima poderia (e deveria) ser escrita sem o uso
de pipe (|
), da seguinte forma:
$ xargs -n 2 < arq.ls
Outra opção legal do xargs
é a -p
, na qual o xargs
pergunta
se você realmente deseja executar o comando. Digamos que em
um diretório você tenha arquivo com a extensão .bug
e .ok
,
os .bug
estão com problemas que após corrigidos são salvos
como .ok
. Dá uma olhadinha na listagem deste diretório:
$ ls dir
arq1.bug
arq1.ok
arq2.bug
arq2.ok
...
arq9.bug
arq9.ok
Para comparar os arquivos bons com os defeituosos, fazemos:
$ ls | xargs -p -n2 diff -c
diff -c arq1.bug arq1.ok ?...y
....
diff -c arq9.bug arq9.ok ?...y
Para finalizar, o xargs
também tem a opção -t
, onde vai
mostrando as instruções que montou antes de executá-las. Gosto
muito desta opção para ajudar a depurar o comando que foi
montado.
Então podemos resumir o comando de acordo com a tabela a seguir:
Opção | Ação |
---|---|
-i | Substitui o par de chaves ({} ) pelas cadeias recebidas |
-nNum | Manda o máximo de parâmetros recebidos, até o máximo de Num para o comando a ser executado |
-lNum | Manda o máximo de linhas recebidas, até o máximo de Num para o comando a ser executado |
-p | Mostra a linha de comando montada e pergunta se deseja executá-la |
-t | Mostra a linha de comando montada antes de executá-la |
Acabou! Foi bom para mim, foi bom para você também? :)
This policy contains information about your privacy. By posting, you are declaring that you understand this policy:
This policy is subject to change at any time and without notice.
These terms and conditions contain rules about posting comments. By submitting a comment, you are declaring that you agree with these rules:
Failure to comply with these rules may result in being banned from submitting further comments.
These terms and conditions are subject to change at any time and without notice.
Comentários (1)
Excelente texto Rubens!!! Mas não teria faltado falar da opção -P para a execução em paralelo?