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: 29 de setembro de 2021
Nas Expansões de Parâmetros que trabalham com texto, sempre podemos usar também os coringas de expansão de nomes de arquivos (globbing) e a extensão desses padrões (extglob) que vimos no início desta série de arquivos.
Nos exemplos a seguir usaremos:
Arq=/usr/share/icons/gnome/scalable/places/debina-swirl.svg Magica=Abracadabra Dt=27/09/2021
Para ficar com MÊS/ANO:
$ echo ${Dt#*/} # Tudo (*) até a barra 09/2021 $ echo ${Dt#???} # 3 caracteres (???) 09/2021 $ echo ${Dt#[0-9][0-9]/} # 2 algarismos ([0-9][0-9]) e a barra 09/2021 $ echo ${Dt#+([0-9])/} # No 1º artigo falo sobre extglb 09/2021
Excluindo o caminho completo do diretório, ou seja, tudo até a última barra
(/
), seria o mesmo que o comando basename
, só que muuuuuito mais rápido
$ BaseName=${Arq##*/}; echo $BaseName
debina-swirl.svg
Excluindo o nome do arquivo, ou seja, tudo a partir da última barra (/
),
seria o mesmo que o comando dirname
, só que muuuuuito mais rápido.
$ DirName=${Arq%/*}; echo $DirName
/usr/share/icons/gnome/scalable/places
Só para você ver que como as Expansões de Parâmetros são velozes. Vou
executar 2000 vezes o comando dirname
e fazer o mesmo usando Expansões de
Parâmetros. Veja:
$ time for ((i=1; i<2000; i++)); { dirname $Arq > /dev/null; } real 0m2.193s user 0m0.288s sys 0m0.364s $ time for ((i=1; i<2000; i++)); { : ${Arq%/*}; } real 0m0.025s user 0m0.024s sys 0m0.000s
É brincadeira? Pelas minhas contas deu 90 vezes mais rápido. Experimente fazer outras comparações do tipo comandos vs Expansões de Parâmetros.
E aí você me pergunta:
— Tá tudo muito bom, mas me diga: Já sei como pegar o dia (${Dt%%/*}
)
e como pegar ano (${Dt##*/}
). Mas e para ficar só com o mês?
— Então presta atenção que lá vem uma carga pesada de macetes
$ : ${Dt#*/}; echo $_ 09/2021 $ echo O Mês é ${_%/*}; echo Agora '$_' ficou com $_ O Mês é 09
Agora $_
ficou com 09
Ou seja, o comando mais rápido que existe é o :
(que é o mesmo que o true
-
experimente também true ${Dt#*/}
) e a saída de qualquer Expansão de
Parâmetros é armazenada na variável $_
que pode ser usada para concatenar
Expansões de Parâmetros.
Agora experimente você fazer aquele loop de 2000 vezes com o comando
cut -f2 -d/ <<< $Dt >/dev/null
e comparar com as duas Expansões de Parâmetros
: ${Dt#*/}; : ${_%/*}
Você terá uma surpresa com os tempos ...
Idêntico aos outros, uma barra (/
) troca a primeira ocorrência, duas
trocam todas:
$ echo ${Magica/a/X} AbrXcadabra $ echo ${Magica//a/X} AbrXcXdXbrX $ echo ${Magica//[Aa]/X} XbrXcXdXbrX
Agora vou dar uma aprofundada pelo campo da extglob. Suponha que seu
programa leia uma resposta para a variável $Resp
, ela poderá conter s
,
sim
, y
ou yes
em caixa alta ou baixa. Para criticar o conteúdo
de $Resp
, podemos fazer:
$ Resp=sIm; : ${Resp^^} # Tudo em Maiúscula
$ Resp=${_/@(S|SIM|YES|Y)/S} # Se for uma das aceitas, vira S
$ echo $Resp
S
$ Resp=n; : ${Resp^^}
$ Resp=${_/@(S|SIM|YES|Y)/S}
$ echo $Resp
N
Agora basta testar se $Resp
não é igual a S
...
Esse foi um exemplo didático, pois o novo comando test
([[ ... ]]
)
também aceita extglob e Expansões de Parâmetros, então ficaria melhor
se fosse:
[[ ${Resp^} == @(S|SIM|YES|Y)/S} ]] && echo Resposta certa
Isso substitui o cut -c
com muita vantagem. Para cortar $Var1
da posição 2
(origem zero) com 3 caracteres, faça:
$ Var1=cadeia $ Seq=123456 $ echo ${Seq:2:3} # Da posição 2 (origem zero) com 3 caracteres 345 $ echo ${Var1:2:3} # Idem dei $ echo ${Var1:2} # Da posição 2 até o fim deia $ echo ${Var1:2: -1} # Da posição 2 até uma posição antes do fim dei $ echo ${Var1: -4} # Da 4a posição antes do fim até o fim deia $ echo ${Var1: -4: -1} # Da 4a posição antes do fim até uma antes dei
Depois dessa, nunca mais use wc -c
.
$ echo $Magica # Só para lembrar Abracadabra $ echo ${#Magica} 11
O que chamo de indireção é quando uma variável armazena o nome de outra e é dessa última que nos interessa o valor. Ou seja, a primeira variável aponta para a que tem o valor que nos interessa.
Exemplo:
$ Var1=Var2 # Var 1 apontando para Var2 $ Var2=Valor_que_desejamos
O que chamo de indireção é quando quero pegar um valor indiretamente, isto é, estamos a fim de Valor_que_desejamos, mas só temos como referência Var1. Isso se faz da seguinte forma:
$ echo ${!Var1}
Valor_que_desejamos
Um exemplo mais palpável. Podemos saber qual foi o último parâmetro passado fazendo o seguinte:
$ echo ${!#}
Onde #
(que dentro de uma Expansão de Parâmetros é o mesmo que $#
) significa
o total de parâmetros passados. Então suponha que tenham passado 3 parâmetros,
quando então $#
teria 3 e eu quero listar o último deles, ou seja, o $3
. Então
essa Expansão de Parâmetros lista o valor da variável que está sendo apontada
por $#
, isto é, $3
.
$ set {a..f} # Expande para a b c d e f $ echo $# 6 $ echo ${!#} f
${!PREFIXO@}
${!PREFIXO*}
Ambas expandem para os nomes das variáveis prefixadas por PREFIXO
. A lista
gerada será separada pelo primeiro caractere da variável $IFS
.
Vamos listar os nomes das variáveis do sistema começadas com a cadeia GNOME
(os nomes, não os seus valores):
$ echo ${!GNOME@} GNOME_DESKTOP_SESSION_ID GNOME_KEYRING_PID GNOME_KEYRING_SOCKET $ echo ${!GNOME*} GNOME_DESKTOP_SESSION_ID GNOME_KEYRING_PID GNOME_KEYRING_SOCKET
Para finalizar, é necessário dizer que as Expansões de Parâmetros também se aplicam a vetores e aos parâmetros posicionais (aqueles que passamos para programas ou funções), sendo que nesses últimos, muitas vezes atuam com comportamento diferente do que mostramos.
Vou dar só um exemplo desse uso:
$ set {a..j} $ echo $@ a b c d e f g h i j $ echo ${@:0:3} bash a b $ echo ${@:1:3} a b c
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