Aula 10 – Expansões de Parâmetros

Aula 9 – Expansões do Shell | Índice | Aula 11 – O loop ‘for’


Seu apoio é muito importante para a criação e a manutenção dos cursos gratuitos do canal debxp:


10.1 – Trocando o nome pela pessoa

A expansão de parâmetros é o que acontece quando o shell substitui a ocorrência de um nome de variável prefixado com um cifrão ($) pelo valor armazenado na variável, como nós temos visto desde a Aula 4:

:~$ fruta=banana
:~$ alunos=(João Maria Sofia José)
:~$ echo $fruta
banana
:~$ echo ${aluno[2]}
Sofia

Note que o cifrão antes de substituições de comando e expansões aritméticas também tem, de certo o modo, a mesma função dos casos acima: indicar para o shell que ele deve substituir o que vem em seguida por um valor. A diferença é que este valor, em vez de estar armazenado numa variável, é o resultado de uma expressão ou a saída de um comando.

A rigor, o nome da variável deveria ser escrito entre chaves (${nome }), mas isso é opcional no caso das variáveis escalares:

:~$ fruta=banana
:~$ echo ${fruta}
banana

Na prática, quando se trata de variáveis escalares, as chaves só são utilizadas quando nós queremos separar o nome da variável do restante da string com que ela será concatenada. Por exemplo:

:~$ prefixo=im
:~$ echo ${prefixo}possível
impossível

Aqui, sem as chaves, o nome da variável a ser expandida ficaria $prefixopossível, e não é isso que nós queremos.

As chaves também não são exatamente obrigatórias quando trabalhamos com arrays, mas o valor expandido será apenas o do primeiro elemento (índice ”0”), quando forem arrays indexadas, ou o último a ser atribuído, nas arrays associativas.

:~$ alunos=(João Maria José)   # Array indexada...
:~$ echo $alunos
João

:~$ declare -A notas    # Array associativa...
:~$ notas[jonas]=8
:~$ notas[joana]=10
:~$ notas[lucas]=9
:~$ echo $notas
9

No caso das arrays, as chaves servem para dizer ao shell que o conteúdo dos colchetes deve ser interpretado como o índice do elemento que contém o valor que nós queremos…

:~$ echo ${alunos[1]}
Maria
:~$ echo ${notas[joana]}
10

10.2 – Indireções

Outra expansão que nós já vimos no curso, só não ligamos o nome à pessoa, foi quando falamos de arrays e explicamos como fazer para listar os índices em vez dos valores de cada elemento. Por exemplo:

# Retornando valores...

:~$ alunos=(João Maria José)
:~$ echo ${alunos[@]}
João Maria José

# Retornando os índices...

:~$ alunos=(João Maria José)
:~$ echo ${!alunos[@]}
0 1 2

Mas, quando o caractere exclamação (!) aparece antes do nome de uma variável escalar entre chaves, ele faz com que o Bash execute a chamada expansão indireta (ou indireção), que é quando o valor de uma variável corresponde ao nome de outra variável, como no exemplo abaixo:

:~$ fruta=banana
:~$ banana=amarela
:~$ echo ${fruta}
banana
:~$ echo ${!fruta}
amarela

Se o nome da variável escalar estiver seguido dos caracteres * ou @, o comportamento da expansão se altera para retornar uma lista de nomes de variáveis que correspondem a um padrão inicial. Por exemplo:

# Encontrando variáveis pelo padrão no nome...

:~$ aluno_1=João
:~$ aluno_2=Maria
:~$ aluno_3=José
:~$ echo ${!aluno*}
aluno_1 aluno_2 aluno_3

Fica bem claro, portanto, que a expansão de parâmetros é muito mais poderosa do que a simples substituição de um nome por um valor. Dentro das chaves, nós podemos utilizar diversos outros símbolos para processar de muitas formas os valores armazenados em uma variável.

10.3 – Substrings

Não é raro nós precisarmos apenas de um “pedaço” de uma string em vez de todo o seu conteúdo. Em programação, esse “pedaço” é chamado de substring.

Considere a string abaixo:

:~$ minha_string=1234567890abcdefghij

Se eu quiser apenas tudo que vier depois do sétimo caractere, basta colocar dois pontos ( : ) após o nome da variável e o número correspondente à última posição que deve ser descartada (no caso, 7):

:~$ echo ${minha_string:7}
890abcdefghij

Nós também podemos indicar quantos caracteres queremos ver a partir da posição indicada. Basta incluir novamente os dois pontos ( ”:” ) seguido da quantidade desejada. Veja os exemplos:

:~$ echo ${minha_string:7:0}    # Não retorna nada...

:~$ echo ${minha_string:7:1}
8
:~$ echo ${minha_string:7:2}
89
:~$ echo ${minha_string:7:3}
890

Também podemos iniciar a contagem da posição a partir do fim da string…

:~$ minha_string=1234567890abcdefghij
:~$ echo ${minha_string: -7}
defghij

Repare em duas coisas no exemplo:

  • Antes do -7, existe um espaço;
  • A substring retornada contém os 7 últimos caracteres da string.

Ou seja, quando contamos a partir do fim, estamos definindo a quantidade de caracteres que nos interessam, e não a quantidade de caracteres da parte que não nos interessa, como fizemos antes.

Reforçando a ideia:

# Descarta os 7 primeiros caracteres e retorna o restante da string...
:~$ echo ${minha_string:7}
890abcdefghij

# Retorna os 7 últimos caracteres...
:~$ echo ${minha_string: -7}
defghij

As quantidades de caracteres também podem ser negativas. Por exemplo:

:~$ minha_string=1234567890abcdefghij
:~$ echo ${minha_string:7:-2}
890abcdefgh

Aqui, o valor foi expandido para todos os caracteres depois da posição 7 menos os dois últimos caracteres.

Outros exemplos:

:~$ minha_string=1234567890abcdefghij
:~$ echo ${minha_string: -7} # Retorna os 7 últimos caracteres
defghij
:~$ echo ${minha_string: -7:2} # Dos 7 últimos caracteres, retorna apenas os 2 primeiros...
de
:~$ echo ${minha_string: -7:-2} # Dos 7 últimos caracteres, descarta os 2 últimos...
defgh

Importante! O espaço antes de uma posição negativa é obrigatório e necessário para diferenciar a indicação de uma contagem negativa (: -7) do símbolo de uma outra expansão de parâmetro (:-), utilizada para definir o valor padrão de uma variável caso ela não tenha sido definida.

Por exemplo:

:~$ minha_var=teste
:~$ echo ${minha_var:-banana}
teste
:~$ unset minha_var
:~$ echo ${minha_var:-banana}
banana

Mas isso é assunto para outro tópico mais adiante.

10.4 – Comprimento de strings e número de elementos de arrays

Para saber o número de caracteres de uma string, nós utilizamos a cerquilha (#) antes do nome da variável:

:~$ fruta=banana
:~$ echo ${#fruta}
6

Mas, se estivermos trabalhando com uma array, o shell expandirá o número de elementos que ela contém:

:~$ echo ${#alunos[@]}
3

A título de exercício, você sabe explicar por que o código abaixo retorna 4? Uma pista: pense no que está realmente sendo retornado pela expansão abaixo.

:~$ alunos=(João Maria "Luis Carlos")
:~$ echo ${#alunos}
4

10.5 – Testando variáveis

Através das expansões de parâmetros, nós podemos testar se uma variável foi ou não definida e dizer ao shell o que fazer em cada caso. É aí que entram os símbolos abaixo:

Expansão Descrição
${nome:-valor_padrao} Caso nome não exista ou seja nulo, o shell expande valor_padrao.
${nome:=valor_padrao} Caso nome não exista ou seja nulo, o shell expande valor_padrao e atribui valor_padrao a nome.
${nome:?mensagem} Caso nome não exista ou seja nulo, o shell escreve mensagem na saída de erro e termina a execução se estiver no modo não-interativo.
${nome:+valor_padrao} Caso nome não exista ou seja nulo, nada é expandido. Se nome existir, valor padrão é expandido.

Essas quatro expansões cobrem muitos problemas que nós resolveríamos com o comando test ou com uma estrutura de decisão if.

Exemplo 1: a variável minha_var não existe…

:~$ echo ${minha_var:-Este é o padrão}
Este é o padrão
:~$ echo $minha_var

:~$

Exemplo 2: a variável minha_var não existia

:~$ echo ${minha_var:=Este é o padrão}
Este é o padrão
:~$ echo $minha_var
Este é o padrão

Exemplo 3: gera um erro se a variável minha_var não existir…

:~$ echo ${minha_var:?"A variável 'minha_var' não existe!"}
bash: minha_var: A variável 'minha_var' não existe!

Exemplo 4: a variável minha_var existe!

:~$ minha_var=teste
:~$ echo ${minha_var:+Este é o padrão}
Este é o padrão
:~$ echo $minha_var
teste

10.6 – Maiúsculas e minúsculas

É muito fácil alterar a caixa (alta ou baixa) dos caracteres de uma string com as expansões de parâmetros.

Expansão Descrição
${variavel^} Primeiro caractere em caixa alta.
${variavel^^} Todos os caracteres em caixa alta.
${variavel,} Primeiro caractere em caixa baixa.
${variavel,,} Todos os caracteres em caixa baixa.

Exemplos:

# Caixa alta...

:~$ fruta=banana
:~$ echo ${fruta^}
Banana
:~$ echo ${fruta^^}*
BANANA

# Caixa baixa...

:~$ fruta=LARANJA
:~$ echo ${fruta,}
lARANJA
:~$ echo ${fruta,,}
laranja

10.7 – Aparando strings

Além das substrings, nós também podemos aparar (trim) o início ou o fim de uma string a partir de padrões de correspondência. Isso é possível com o uso dos símbolos # ou %.

Expansão Descrição
${variavel#padrão} Todo o início da string será aparado até a primeira ocorrência do padrão.
${variavel##padrão} Todo o início da string será aparado até a últimaocorrência do padrão.
${variavel%padrão} Todo o fim da string será aparado até a primeira ocorrência do padrão de trás para frente.
${variavel%%padrão} Todo o fim da string será aparado até a última ocorrência do padrão de trás para frente.

Nos exemplos abaixo, observe que o padrão é *ba, significando: "caracteres b e a antecedidos de qualquer ou nenhum caractere". Observe também que a string em frutas possui duas ocorrências da sequência ba.

Portanto…

# O padrão casa com tudo até a primeira ocorrência de 'ba'...

:~$ frutas='banana laranja abacate'
:~$ echo ${frutas#*ba}
nana laranja abacate

# O padrão casa com tudo até a última ocorrência de 'ba'...

:~$ frutas='banana laranja abacate'
:~$ echo ${frutas##*ba}
cate

Sem o metacarectere *, porém, nós teríamos resultados iguais…

:~$ frutas='banana laranja abacate'
:~$ echo ${frutas#ba}
nana laranja abacate
:~$ echo ${frutas##ba}
nana laranja abacate

Isso porque, na segunda expansão, ba só casa com os dois primeiros caracteres da string. Por isso nós utilizamos os meta caracteres para representar os padrões. Dentre eles, os mais importantes no momento são:

Meta Descrição
* Casa com qualquer quantidade de caracteres ou nenhum caractere.
? Casa com um único caractere qualquer existente.
[...] Casa com um único caractere existente do listado entre os colchetes.

Nos exemplos abaixo, nós veremos como aparar o final de uma string a partir de uma busca reversa pelo padrão:

# O padrão casa com a mínima correspondência reversa iniciada com 'an'...

:~$ frutas="banana laranja abacate"
:~$ echo ${frutas%an*}
banana lar

# O padrão casa com a máxima correspondência reversa iniciada com 'an'...

:~$ frutas="banana laranja abacate"
:~$ echo ${frutas%%an*}
b

10.8 – Busca e substituição de padrões

Existem ótimas ferramentas disponíveis na linha de comandos para realizar buscas e substituições de padrões de strings, como os utilitários sed, awk e tr, por exemplo. Mas o Bash oferece uma solução bem mais rápida para esse tipo de operação com as suas expansões.

Expansão Descrição
${variavel/padrão/string} Substitui a primeira ocorrência de ‘padrão’ por ‘string’.
${variavel//padrão/string} Substitui todas as ocorrências de ‘padrão’ por ‘string’.

Por exemplo:

:~$ mensagem="Use Windows e seja feliz!"

# Casa com 'Windows'

:~$ echo ${mensagem/Windows/Linux}
Use Linux e seja feliz!

# Casa com 'W', qualquer coisa, e o 's' seguido de espaço...

:~$ echo ${mensagem/W*s /Linux }
Use Linux e seja feliz!

# Casa com 'W' seguido de qualquer coisa até o último espaço...

:~$ echo ${mensagem/W* /Linux }
Use Linux feliz!

# Substituindo todas as ocorrências do padrão 'te' pela string 'tche'...

:~$ compras="leite mate chocolate"
:~$ echo ${compras//te/tche}
 leitche matche chocolatche

Aula 9 – Expansões do Shell | Índice | Aula 11 – O loop ‘for’

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Post comment