Revista Do Linux
EDIÇÃO DO MÊS
 CD do Mês

 Capa
 Entrevista
 Corporativo
 Distro
 Segurança
 Hardware
 Produto
 Primeiros Passos
 Sistema
 

Grupos de comandos Expansão de strings e nomes de arquivos

O Bash permite agrupar comandos, que desse modo são executados como uma única unidade. Podemos agrupar os comandos de duas formas:

1) Agrupamento por parênteses, "( )": Comandos colocados entre parênteses e separados por ponto-e-vírgula, ";", são agrupados e executados serialmente invocando um subshell. Exemplo:

# (ls; du; find -name \*.txt)	

2) Agrupados por chaves, "{ }":

Comandos colocados entre chaves e separados por ponto-e—vírgula, ";", são agrupados e executados serialmente no shell corrente. Exemplo:

# {ls; du; find -name \*.txt}

Você deve estar pensando: "Para que eu agruparia meus comandos? Para deixá-los mais bonitos?" Não!

A vantagem de vários comandos agrupados pode ser vista quando precisamos desviar a saída desses comandos. Imagine que você precise fazer um script para executar vários comandos e obter a saída de erros de cada comando colocado no script. Seria assim:

...
comando1 2>erros.txt
comando2 2>>erros.txt
comando3 2>>erros.txt
comando4 2>>erros.txt
...

Com o agrupamento isso fica mais fácil e simples:

...
(
comando1 ; 
comando2 ;
comando3 ;
comando4 ;
) 2>erros.txt
...

Observe que no primeiro exemplo desviamos o erro para cada comando e no segundo exemplo o desvio foi feito para todos os comandos em uma única vez.

Se esse exemplo fosse passado para a linha de comando ficaria desta forma: exemplo 1:

# comando1 2>erros.txt; comando2 2>>erros.txt ; comando3 2>>erros.txt comando4 >>erros.txt

exemplo 2:

#(comando1;comando2;comando3;comando4;) 2> erros.txt

Você concorda que, com agrupamento, a linha de comando fica até mais legível! Agora vamos imaginar que você precise tratar a saída de vários comandos, por exemplo, alterar de minúsculo para maiúsculo. Você poderia escrever assim:

# cat /etc/hosts | tr a-z A-Z > saida.txt ; 
cat /etc/resolv.conf |tr a-z A-Z >>saida.txt ; 
cat /etc/sysconfig/network | tr a-z A-Z >>saida.txt

Mas o ideal seria:

# (cat /etc/hosts ; cat /etc/resolv.conf ; 
cat /etc/sysconfig/network; )| tr a-z A-Z >>saida.txt

No segundo exemplo, além de ficar mais legível, o comando "tr" é executado uma única vez, já no primeiro exemplo cada um dos comandos será executado.

A diferença entre os grupos criados com parênteses, "( )", ou os criados com chaves, "{ }", pode ser vista no comando abaixo:

# VAR="ANTES";(VAR="DEPOIS";VAR="ADIANTE";); echo $VAR
ANTES

# VAR="ANTES";{VAR="DEPOIS";VAR="ADIANTE";}; echo $VAR
ADIANTE

Observe que no exemplo escrito com parênteses a variável VAR retornou ao mesmo valor que fora atribuído antes de executar o grupo de comandos. Isso se deve ao fato de que os comandos são executados em subshell. Já no exemplo escrito com chaves a variável VAR retornou ao último valor que fora atribuído, porque grupos feitos com chaves são executados no shell corrente.

Expansão de strings

Expansão de strings é um mecanismo que combina uma expressão inicial com um conjunto de caracteres. Exemplo:

#echo a{1,2,3}
a1 a2 a3

As combinações são feitas entre os elementos que estão entre as chaves separados por vírgula, da esquerda para a direita.

Podemos combinar mais que um conjunto de caracteres simultaneamente:

# echo a{1,2,3}b{1,2,3}
a1b1 a1b2 a1b3 a2b1 a2b2 a2b3 a3b1 a3b2 a3b3

Combinar dois conjuntos separadamente também é possível, basta colocar os conjuntos entre chaves e separá-los por vírgula.

# echo {a{1,2,3},b{1,2,3}}
a1 a2 a3 b1 b2 b3

A grande vantagem da expansão está na expansão de nomes de arquivos, que é utilizada em comandos que recebem como parâmetro um ou mais nome de arquivos. Exemplo:

# ls /dev/hda
|
|––> Este é o parâmetro do ls que deve ser um diretório ou um arquivo 
Imagine que você queira listar todos os arquivos do diretório /dev que inicie com hda e termine com 1, 2 ou 3.

# ls /dev/hda{1,2,3}
/dev/hda1 /dev/hda2 /dev/hda3

Podemos combinar dois conjuntos também:


# ls /dev/{hda{1,2,3},hdb{1,2,3}}

/dev/hda1 /dev/hdb1
/dev/hda2 /dev/hdb2
/dev/hda3 /dev/hdb3

Adicionar metacaracteres também é possível:

# ls /dev/{hd?{1,2,3}}
/dev/hda1 /dev/hdb1 /dev/hdc1 /dev/hdd1
/dev/hda2 /dev/hdb2 /dev/hdc2 /dev/hdd2
/dev/hda3 /dev/hdb3 /dev/hdc3 /dev/hdd3

Os metacaracteres suportados em expansão são:

* — Um ou mais caracteres

# ls /dev/{hd{a,b,c}*}
/dev/hda1 /dev/hdb1 /dev/hdc1 
/dev/hda11 /dev/hdb11 /dev/hdc11 
/dev/hda2 /dev/hdb2 /dev/hdc2 
/dev/hda3 /dev/hdb3 /dev/hdc3

? — Exatamente um caractere

# ls /dev/{hd{a,b,c}?}
/dev/hda1 /dev/hdb1 /dev/hdc1 
/dev/hda2 /dev/hdb2 /dev/hdc2 
/dev/hda3 /dev/hdb3 /dev/hdc3

[abc] — Combina com a, b ou c

# ls /dev/{hd[abc]{1,2,3}}
/dev/hda1 /dev/hdb1 /dev/hdc1
/dev/hda2 /dev/hdb2 /dev/hdc2
/dev/hda3 /dev/hdb3 /dev/hdc3

[a-z] — Combina o range de "a" a "z"

# ls /dev/{hd[a-c]{1,2,3}}
/dev/hda1 /dev/hdb1 /dev/hdc1
/dev/hda2 /dev/hdb2 /dev/hdc2
/dev/hda3 /dev/hdb3 /dev/hdc3

[!a-z] — Não combina o range de "a" a "z"

# ls /dev/{hd[!a-c]{1,2,3}}
/dev/hdd1 /dev/hde1 /dev/hdf1
/dev/hdd2 /dev/hde2 /dev/hdf2
/dev/hdd3 /dev/hde3 /dev/hdf3

Espero ter contribuído mais um pouco para o aprendizado dos leitores.

Até a próxima edição!


A Revista do Linux é editada pela Conectiva S/A
Todos os Direitos Reservados.

Política de Privacidade
Anuncie na Revista do Linux