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 maio de 2021
Algumas variáveis do sistema têm um comportamento muito interessante que no
meu entender, merece a atenção daqueles que gostam de usar o Shell. Neste
artigo mostrarei uma "façanha" diferente, que é você alterar o valor de uma
variável somente para executar uma única instrução, voltando ao conteúdo
anterior ao término deste comando. As mais importantes são o uso da IFS
e
das variáveis de localidade. Primeiro uma breve descrição delas:
IFS
(Inter Field Separator) é a variável que estipula os
delimitadores de campo para diversos comandos. Por default seu valor é formado
por espaço em branco, <TAB>
e <ENTER>
, mas este valor pode ser alterado. Para
exemplificar usarei o comando read
, com o qual eu posso ler de uma só vez
diversos campos, desde que sejam separados por algum caractere da IFS
. Veja:
$ read Cpo1 Cpo2 Cpo3 <<< "A B C"
$ echo +$Cpo1+ -- +$Cpo2+ -- +$Cpo3+
+A+ -- +B+ -- +C+
Ou seja, cada uma das variáveis recebeu um valor já que os dados da entrada
eram separados por espaços em branco. Mas e se a entrada vier delimitada
por dois pontos (:
), assim:
$ read Cpo1 Cpo2 Cpo3 <<< "A:B:C"
$ echo +$Cpo1+ -- +$Cpo2+ -- +$Cpo3+
+A:B:C+ -- ++ -- ++
Xiii! Não funcionou porque os dois pontos (:
) não fazer parte do IFS
. Então
vamos fazê-lo:
$ IFS=: read Cpo1 Cpo2 Cpo3 <<< "A:B:C"
$ echo +$Cpo1+ -- +$Cpo2+ -- +$Cpo3+
+A+ -- +B+ -- +C+
Viu!? Agora funcionou e veja:
$ read Cpo1 Cpo2 Cpo3 <<< $(echo -e "F\tG\nH")
$ echo +$Cpo1+ -- +$Cpo2+ -- +$Cpo3+
+F+ -- +G+ -- +H+
Desta vez os delimitadores eram <TAB>
(\t
) e <ENTER>
(\n
)
mostrando que o IFS
voltou ao seu valor inicial, ou seja, foi alterado
somente para executar um único read
.
As variáveis de localidade, especificam as padronizações dependentes de cada
país. Elas podem ser vistas pelo comando locale
.
$ locale # Suporte a multi linguagem
LANG=pt_BR.UTF-8
LANGUAGE=
LC_CTYPE="pt_BR.UTF-8"
LC_NUMERIC="pt_BR.UTF-8"
LC_TIME="pt_BR.UTF-8"
LC_COLLATE="pt_BR.UTF-8"
LC_MONETARY="pt_BR.UTF-8"
LC_MESSAGES="pt_BR.UTF-8"
LC_PAPER="pt_BR.UTF-8"
LC_NAME="pt_BR.UTF-8"
LC_ADDRESS="pt_BR.UTF-8"
LC_TELEPHONE="pt_BR.UTF-8"
LC_MEASUREMENT="pt_BR.UTF-8"
LC_IDENTIFICATION="pt_BR.UTF-8"
LC_ALL=
A LC_ALL
normalmente está vazia porque ela tem prioridade sobre as outras e
se fosse necessário manter uma variável de localidade fora do formato padrão,
informando um valor para LC_ALL
, todas receberiam essa máscara de local.
Sobre isso, devemos também saber que a localidade C
é um locale especial
que se destina a ser a localidade mais simples. Pode-se dizer que, as outras
localidades são para humanos, mas a C
é para computadores. No local C
,
os caracteres são bytes únicos, o conjunto de caracteres é ASCII. Exceto
LC_MONETARY
, todas as outras definições são iguais a en_US
, ou seja,
tudo no padrão americano.
Vejamos então alguns exemplos de mudanças temporárias no valor das variáveis locais:
$ cat arq 1 a B 2 b A $ sort arq # Ordenação natural 1 2 a A b B $ LC_COLLATE=C sort arq # Ordenação ascii 1 2 A B a b $ man
Qual a página de manual desejada?
$ LANG=C man What manual page do you want? $ echo $LANG # Mudou linguagem só para o man pt_BR.UTF-8
O bc
sempre dá a saída com ponto decimal, isto é, no padrão americano, veja:
$ bc <<< "scale=2 ; 100/6"
16.66
Mas se desejarmos formatar esta saída com 3 decimais, deveríamos fazer:
$ printf '%.3f\n' $(bc <<< "scale=2 ; 100/6")
bash: printf: 16.66: número inválido
0,000
Esse erro ocorreu porque como você pode reparar no comando locale LC_NUMERIC=pt_BR.UTF-8
o que é incompatível com ponto decimal, só aceita vírgula (,
), então é muito
comum vermos construções do tipo:
$ printf "%.3f\n" $(bc <<< "scale=2 ; 100/6" | tr . ,)
16,660
Ou seja: usando o comando tr
para trocar o ponto decimal por vírgula, mas
se o resultado impresso não necessitasse da vírgula, a operação seria bem
mais rápida se fosse feita da seguinte forma:
$ LC_NUMERIC=C printf '%.3f\n' $(bc <<< "scale=2 ; 100/6")
16.660
E agora se olharmos o conteúdo daquela variável, podemos ver que continua o que era antes:
$ locale | grep -F LC_NUMERIC
LC_NUMERIC="pt_BR.UTF-8"
Ou ainda, mais detalhadamente:
$ locale -k LC_NUMERIC
decimal_point=","
thousands_sep="."
grouping=3;3
numeric-decimal-point-wc=44
numeric-thousands-sep-wc=46
numeric-codeset="UTF-8"
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