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ãoif
.
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’