Prévia do material em texto
PROGRAMAÇÃO EM
AMBIENTES DE
REDES DE
COMPUTADORES
Maikon Lucian Lenz
Tipos de dados em
Shell Script Linux
Objetivos de aprendizagem
Ao final deste texto, você deve apresentar os seguintes aprendizados:
� Definir os parâmetros posicionais e as opções da linha de comando.
� Discutir variáveis, variáveis especiais, tipagem dinâmica, strings e arrays.
� Explicar operadores e aritmética.
Introdução
Boa parte da programação tem o objetivo de manipular variáveis, situação
que não é diferente no Shell Script, o qual não define uma tipagem forte,
tratando todos os dados, em última instância, como texto ou string. No
entanto, há casos especiais dessas variáveis, utilizadas para armazenar
identificadores de processo, parâmetros durante o uso de funções e
comandos, além dos vetores, ou arrays.
Neste capítulo, você conhecerá os parâmetros posicionais, como se
definem as variáveis e como seus valores podem ser retornados. Ainda,
verificará como é possível efetuar operações aritméticas mesmo quando
não existem tipos numéricos.
1 Parâmetros posicionais e opções de comandos
Ao invocar um comando, o Shell Script executa o código deste e retorna o
código principal para dar continuidade ao restante da execução. No entanto,
muitas vezes o comportamento do comando deve ser modificado ou os dados
ser fornecidos para executar alguma operação, situações em que se pode fazer
uso de parâmetros e opções, que deverão ser informados com o comando ao
invocá-lo.
Os comandos podem ser tanto invocar um script em outro arquivo para
execução quanto uma função declarada no script atual. A vantagem de usar
funções reside na possibilidade de reutilizar o código quantas vezes seja neces-
sário, bem como organizar o script em módulos que facilitam sua organização
e desenvolvimento. Além disso a função pode ficar carregada na memória,
tornando o acesso ao script nela contido mais rápido (NEWHAM, 2005).
Para enviar valores/argumentos para uma função, são utilizadas as va-
riáveis embutidas do Shell Script conhecidas como parâmetros posicionais,
chamadas assim porque o nome dado a cada argumento corresponde ao índice
numérico da posição em que aparecem na linha de comando que invocou a
função. Assim, da mesma forma como uma variável tem seu valor retornado
pela estrutura $var, em que var corresponde ao nome como a variável em
questão foi declarada, os parâmetros posicionais são nomeados $1, $2, $3,
e assim sucessivamente (NEWHAM, 2005).
O Exemplo 1 visa simplesmente a demonstrar de que maneira os parâmetros
posicionais são utilizados, já que a função imprimir apenas exibe o texto no
console, da mesma forma que o comando echo faria. Porém, nesse caso,
somente a primeira palavra é exibida, exceto se o argumento for iniciado e
encerrado com o uso de aspas.
# Exemplo 1 – Enviando parâmetros posicionais para uma função.
function imprimir
{
echo $1
}
imprimir Olá
Assim, cada parâmetro é delimitado por pelo menos um espaço vazio.
Para evitar que o Shell Script interprete o espaço como um novo argumento,
pode-se colocar um texto contendo espaços entre aspas.
O Exemplo 2 envia quatro parâmetros para a função imprimir. A palavra
Primeiro fica armazenada na variável $1; a palavra teste fica armazenada na
variável $2; a palavra e fica armazenada na variável $3; e, por fim, a variável
$4 retornará todo o texto entre aspas "segundo teste". Obviamente,
o resultado da mensagem exibida na tela será apenas "Primeiro segundo
teste", uma vez que o comando echo exibe $1 e $4 na sequência. Assim,
apesar de $2 e $3 terem as demais palavras ("teste" e "e"), a função
imprimir não as utiliza.
Tipos de dados em Shell Script Linux2
# Exemplo 2 – Enviando parâmetros posicionais para uma função.
function imprimir
{
echo $1 $4
}
imprimir Primeiro teste e "segundo teste"
O índice zero é reservado para informar o nome do script utilizado
(NEWHAM, 2005). Por exemplo, ao utilizar um script em Bash, o comando
echo $0 retornaria simplesmente: -bash.
Há, ainda, três variáveis que se referem aos parâmetros posicionais:
$*, $@ e $# (NEWHAM, 2005).
Para retornar todos os parâmetros posicionais em um único texto, emprega-
-se a variável $*. Se utilizado no Exemplo 4 o comando echo $* no lugar
de echo $1 $4, seria exibido o texto completo "Primeiro teste e
segundo teste".
Já a variável $@ separaria cada um dos argumentos entre aspas "Pri-
meiro", "teste", "e" e "segundo teste".
Por fim, a variável $# retorna a quantidade de argumentos existentes.
E o Exemplo 3 exibiria o valor 3 na tela.
# Exemplo 3 – Quantidade de argumentos.
function imprimir
{
echo $#
}
imprimir argumento1 argumento2 "outro argumento"
No entanto, caso fossem removidas as aspas da frase "outro argu-
mento" do Exemplo 3, o valor exibido no console seria 4, já que a frase em
questão seria compreendida como dois parâmetros distintos em decorrência
do espaço entre as palavras outro ($3) e argumento ($4).
É importante destacar que todas as variáveis utilizadas como parâmetros
posicionais ou como propriedades destes (como é o caso do $#, que expressa
a quantidade de parâmetros, e não um valor específico) são variáveis do tipo
somente leitura, ou seja, não é possível atribuir diretamente um valor a elas,
sendo manipuladas diretamente apenas pelo Shell Script (NEWHAM, 2005).
3Tipos de dados em Shell Script Linux
No caso de não haver parâmetros relacionados, qualquer uma dessas variá-
veis será substituída por textos vazios, e, obviamente, a variável $# terá o valor
0. Em alguns casos, é possível configurar o interpretador utilizado para não
aceitar variáveis não definidas, situação em que os argumentos inexistentes,
quando solicitados, resultarão em uma mensagem de erro (NEWHAM, 2005).
Por fim, essas variáveis podem ser utilizadas da mesma forma para um
arquivo de script, como demonstradas para as funções. Se o código echo $1
fosse escrito em um arquivo e este fosse invocado na linha de comando pelo
comando source arquivo Olá, teríamos o mesmo resultado do Exemplo 1.
As variáveis que armazenam os valores dos parâmetros posicionais podem ser invocadas
diretamente pelo símbolo $ e pelo índice do parâmetro a que se referem. No entanto,
a partir do décimo parâmetro, somente é possível se referir a uma variável correta
utilizando a sintaxe ${nome}. Do contrário, ao utilizar o valor $10, seria exibido o
valor da variável $1 seguido do valor 0; nesse caso, o décimo argumento deve ser
utilizado da seguinte forma: ${10} (ROBBINS; BEEBE, 2005).
Tipos de dados
Qualquer conteúdo pode ser armazenado nas variáveis do Shell Script.
Na verdade, as variáveis nada mais são que um nome utilizado com referência
para um endereço de memória — sem nenhuma outra especificação, sempre
que se faz uma atribuição a uma variável, o Shell Script relaciona um endereço
de memória ao nome escolhido, facilitando, assim, a referência aos dados
armazenados.
Ao contrário do que ocorre em algumas linguagens de programação,
o Shell Script em si não diferencia os tipos de variáveis, de modo que qualquer
valor será sempre armazenado como um texto. Assim, o Shell Script dispõe de
um sistema de tipagem dinâmica, ou seja, a variável pode assumir diferentes
valores e o próprio interpretador se encarregará de determinar o tipo mais
adequado. Graças a isso, mesmo que uma variável já tenha sido declarada,
pode receber qualquer tipo de dado a qualquer momento (NEWHAM, 2005).
Tipos de dados em Shell Script Linux4
As restrições na declaração de variáveis se limitam à não utilização de
caracteres especiais e espaços com exceção do underline ( _). Também não se
pode iniciar uma variável com números, que, como visto anteriormente, corres-
pondem a valores reservados para se referir aos argumentos de um comando.
Ainda, não se deve separar o nome da variável do símbolo de atribuição (=)
do valor; do contrário o interpretador teria dificuldades em distinguir o que
é um argumento de um operador (ALBING; VOSSEN, 2017).
Apesarde todas as variáveis serem do tipo texto, existem operadores
designados especificamente para tratar o conteúdo das variáveis envolvidas
como numéricos (ALBING; VOSSEN, 2017).
Todas as variáveis declaradas em um mesmo script estão acessíveis em
qualquer parte do código. Ainda que uma variável seja declarada dentro de
uma função, no momento em que está função seja executada, o nome e seu
respectivo endereço de memória ficarão acessíveis fora desta.
Para que uma variável somente seja acessível localmente, torna-se ne-
cessário declarar explicitamente pela palavra local, como no Exemplo 4.
# Exemplo 4 – Variável local.
function teste
{
A=2
B=3
local C=4
local D=6
}
A=1
D=5
teste
echo $A $B $C $D
5Tipos de dados em Shell Script Linux
Inicialmente, é atribuído o valor 1 para a variável A e o valor 5 para a
variável D. Na sequência, é invocada a função teste, alterará o valor de A para
2, criará uma nova variável acessível fora da função com o valor 3 de nome B,
criará uma variável local de nome C com o valor 4 e criará uma variável local
de nome D com valor 6. Pelo comando echo $A $B $C $D, somente três
valores seriam exibidos, já que não existe uma variável com nome C fora da
função teste, mas uma variável de nome D fora dela, ainda que de valor diferente
da variável interna. Assim, os valores exibidos na tela seriam: 2 (variável A),
3 (variável B) e 5 (variável D não local). Mas, caso fosse solicitada a variável
D dentro da função, esta teria o valor 6 atribuído localmente, demonstrando
que, de fato, se referem a variáveis e endereços de memória diferentes.
É possível inclusive tornar as variáveis de um script acessíveis a outros
scripts pelo comando export seguido do nome da variável que se deseja exportar
(ALBING; VOSSEN, 2017).
Existem outras variáveis especiais além das utilizadas pelos parâmetros
posicionais: $?, $$, $! e $_, descritas no Quadro 1.
Fonte: Adaptado de Newham (2005).
Variável Descrição
$? Armazena o estado de saída do último comando executado
$$ Armazena o número de identificação do processo ou subprocesso
em que o código/script atual está inserido
$! Armazena o número de identificação do último processo
executado assincronamente, ou seja, do último processo
executado em segundo plano
$_ Armazena o último argumento do último comando executado
Quadro 1. Variáveis especiais não posicionais
A variável $? é utilizada para verificar o estado de saída de um comando
previamente executado, sendo possível determinar, por exemplo, se este fora
executado com sucesso ou retornou algum erro (ALBING; VOSSEN, 2017).
Tipos de dados em Shell Script Linux6
Suponha que o script da Figura 1 seja executado dentro de um diretório
em que apenas uma pasta de nome Home se faz presente. Aqui, caso tentasse
acessar uma pasta de nome Teste, o comando cd retornaria o valor 1, que
indica a inexistência da pasta solicitada. Porém, se tentasse acessar a pasta de
nome Home, o comando cd retornaria o valor 0, além de mudar o diretório
atual. Esses valores de estado de saída são acessíveis pelo comando $? se
executados imediatamente após o comando, conforme podemos observar na
Figura 1, em que o primeiro comando (ls) demonstra a existência de apenas
uma pasta de nome Home.
Figura 1. Uso da variável especial $? para acessar o estado de
saída do último comando executado.
Pode-se usar a variável $$ para informar o identificador do processo ao qual
o script atual pertence (ALBING; VOSSEN, 2017), sendo muito utilizada quando
há constante comunicação de dados entre processos, em que um novo processo
é invocado informando como parâmetro o número do processo atual, de modo
que o novo processo saiba para qual identificador deverá retornar o resultado.
Podemos compreender facilmente a função da variável $$ pela Figura 2,
em que, inicialmente, um comando ps é executado, para listar todos os pro-
cessos existentes. Perceba que, na sequência, o valor exibido da variável $$
é o mesmo do único interpretador Bash executado. Ao final, cria-se uma
instância do interpretador Bash, e o valor da variável $$ coincidirá com o
processo atual novamente.
7Tipos de dados em Shell Script Linux
Figura 2. Uso da variável especial $$ para
descobrir o identificador do processo ao
qual o script atual pertence.
Por meio do operador &, é possível criar um processo secundário para
executar um comando (BLUM, 2008). Assim, o console fica livre para ser
utilizado enquanto o script é executado em segundo plano. Nesse caso, dizemos
que está sendo executado um processo assíncrono, já que o script principal
não aguarda o término de um comando para poder efetuar outros. A variável
$! identifica o processo ao qual pertence o último comando executado em
segundo plano.
A Figura 3 demonstra a utilização da variável $!: primeiro, ela não tem
valor nenhum e, após a execução síncrona do comando pwd, que exibe o
caminho da pasta atual, não há qualquer alteração no seu valor. No entanto,
se o mesmo comando pwd é executado com o operador & (pwd &), então
é criada uma instância do interpretador para executá-lo e, ao concluir, é o
identificador dessa instância que poderá ser lido na variável especial.
Tipos de dados em Shell Script Linux8
Figura 3. Uso da variável especial $! para descobrir
o identificador do último processo executado em
segundo plano.
A variável $_ por sua vez, simplesmente retorna o último parâmetro do
último comando executado (NEWHAM, 2005). Na Figura 4, é executado o
comando ping com três parâmetros, e o comando echo $_ retorna somente
o último deles: o endereço de rede utilizado.
Figura 4. Uso da variável especial $_ para retornar o último parâmetro utilizado.
Ainda, as variáveis podem armazenar textos completos, como já dito,
utilizando as aspas duplas para que os espaços não sejam compreendidos
como separador de parâmetros ou comandos.
9Tipos de dados em Shell Script Linux
No Exemplo 5, todas as variáveis apresentam exatamente o mesmo valor.
No entanto, se houver mais palavras com algum espaço vazio entre elas,
somente as variáveis B e C seriam corretamente atribuídas.
# Exemplo 5 – Atribuições de valores
A=Texto
B='Texto'
C="Texto"
A diferença entre a utilização de aspas duplas ou aspas simples está na
maneira como devem ser interpretados os caracteres especiais. Para uma string
em aspas simples, são ignoradas as funções correspondentes aos caracteres
especiais, como o operador $, que simbolizaria uma variável. Nesse caso, o $
aparece no texto como um caractere normal. Caso o $ fosse utilizado em aspas
duplas, seria substituído pelo valor da respectiva variável (NEWHAM, 2005).
No Exemplo 6, o comando echo B exibiria a mensagem Texto $A,
enquanto o comando echo C substituiria o termo $A pelo valor da variável
A, resultando na mensagem Texto 1. A escolha de cada forma de atribuição
depende da necessidade e do que é mais conveniente em cada situação.
# Exemplo 6 – Atribuições de valores
A=1
B='Texto $A'
C="Texto $A"
echo B
echo C
É possível ainda criar um vetor (array) de variáveis, em que todos os índices
têm o mesmo nome, mas se referem a endereços de memória e, portanto, valores
diferentes, diferenciados por meio de um índice entre colchetes associado ao
nome da variável (BLUM, 2008).
Tipos de dados em Shell Script Linux10
Para criar um vetor, o valor atribuído deve ser colocado entre parênteses,
e os espaços delimitam cada um dos índices do vetor (ALBING; VOSSEN,
2017), como no Exemplo 7, em que a variável S é, na verdade, um vetor de
três posições, cujos valores são, respectivamente, 1, 2 e 3.
# Exemplo 7 – Atribuições de valores
S=(1 2 3)
echo ${S[2]}
echo ${S[1]}
echo ${S[0]}
O primeiro valor de um vetor é referenciado pelo índice 0, a partir do
qual se segue a sequência numérica. Assim, cada um dos comandos echo
do Exemplo 7 apresentaria a mensagem: 3, 2 e 1, respectivamente. Caso um
índice inexistente seja solicitado, retornar-se-á um valor nulo/vazio.
A atribuição devalor para um índice específico de um vetor é feita por meio do nome
da variável seguida do índice entre colchetes. Por exemplo, A[1]=2 atribuiria o valor
2 à posição 1 da variável/vetor de nome A.
Além disso, o tamanho de um vetor pode ser retornado pelo código ${#A[@]}
(ROBBINS; BEEBE, 2005).
2 Operadores lógicos e matemáticos
Operações aritméticas podem ser efetuadas em Shell Script desde que estejam
entre parênteses duplos ((...)) (BLUM, 2008).
Os quatro operadores básicos — +, -, * e / —, também utilizados em
outras linguagens de programação, funcionam da mesma forma para o Shell
Script, obedecendo à ordem do valor operador.
11Tipos de dados em Shell Script Linux
O Exemplo 8 atribui valores para as variáveis A e B e exibe o resultado de
quatro operações diferentes entre si.
# Exemplo 8 – Operações matemáticas básicas.
A=4
B=2
echo $(( A + B ))
echo $(( A - B ))
echo $(( A * B ))
echo $(( A / B ))
Nesse caso, seriam exibidas as mensagens 6, 2, 8 e 2, respectivamente,
para cada uma das operações associadas ao comando echo.
O critério de precedência dessas operações é o mesmo dos operadores
matemáticos convencionais, em que são resolvidas, inicialmente, as divisões e
multiplicações e, depois, as somas e subtrações. Entretanto, é possível alterar
a precedência de uma parte da expressão colocando-a entre parênteses.
Há outros operadores aritméticos, como o incremento (++), decremento (--)
e o operador de módulo (%). Ao incrementar um valor, estamos atribuindo a
variável utilizada ao mesmo valor atual dela com o acréscimo de uma unidade
inteira. No processo de decremento, a situação é a mesma, porém o valor da
variável é diminuído de uma unidade inteira.
No Exemplo 9, ambas as operações terminam com o mesmo valor.
# Exemplo 9 – Operações matemáticas básicas.
A=4
B=4
A=$(( A – 1))
(( B-- ))
Pode-se comparar logicamente os valores por meio de operações de igual-
dade (==), diferença (!=), maior (>) ou menor que (<), e, ainda, maior ou igual
(>=) e menor ou igual (<=), nas quais a variável da esquerda é comparada à
variável da direita; caso a suposição seja verdadeira, é retornado o valor 1,
do contrário, retorna-se o valor 0.
Tipos de dados em Shell Script Linux12
Por fim, é possível efetuar as operações lógicas AND, OR e NOT por meio
dos operadores &, | e ~, respectivamente.
O Exemplo 10 efetua a operação AND entre os valores 15 e 78, que, em
binário, equivalem, respectivamente, aos valores 11112 e 010011102. Uma
vez que esses operadores funcionam bit a bit, o resultado será 0 para cada
bit, em que pelo menos uma das duas variáveis for 0 e 1 para os demais.
O resultado da operação entre bits de duas variáveis, para as operações lógicas
fundamentais AND e OR, dá-se conforme o Quadro 2.
A B AND OR
0 0 0 0
0 1 0 1
1 0 0 1
1 1 1 1
Quadro 2. Variáveis especiais não posicionais
As últimas três linhas do Exemplo 10 são comentários que demonstram
como a operação seria realizada resultando no valor 14.
# Exemplo 10 – Operador &.
A=15
B=78
echo $(( A & B ))
# 0000 1111 = A = 15
# & 0100 1110 = B = 78
# 0000 1110 = & = 14
13Tipos de dados em Shell Script Linux
Da mesma forma, se efetuada uma operação OR entre os valores de A e B,
todos os bits em que pelo menos uma das variáveis fosse verdadeiro também
o seriam no resultado. Novamente, as últimas três demonstram a operação e
o resultado 79 (Exemplo 11).
# Exemplo 11 – Operador |.
A=15
B=78
echo $(( A | B ))
# 0000 1111 = A = 15
# & 0100 1110 = B = 78
# 0100 1111 = | = 79
Por fim, inversões de valor pelo operador lógico NOT (~) terão todos os
bits invertidos de 1 para 0 e de 0 para 1. Uma vez que os valores numéricos
são compreendidos como sinalizados e cada unidade de memória corresponde
a 8 bits, o resultado será o complemento de 2 do valor numérico original, em
que o bit mais significativo representa o sinal, conforme o Exemplo 12.
# Exemplo 12 – Operador ~.
A=15
echo $(( ~A ))
# 0000 1111 = A = 15
# 1111 0000 = ~ = -16
Em todos os casos apresentados, podemos utilizar o operador em conjunto
com o operador de atribuição (=), de modo que a própria variável seja um
dos parâmetros durante a operação. O Exemplo 13 mostra como utilizar as
operações de soma, subtração, multiplicação, divisão, lógica E e lógica OU
em conjunto com o operador de atribuição.
Tipos de dados em Shell Script Linux14
# Exemplo 13 – Operações associadas ao operador de atribuição
(=).
A=52
B=23
echo $(( A+=B ))
echo $(( A-=B ))
echo $(( A*=B ))
echo $(( A/=B ))
echo $(( A&=B ))
echo $(( A|=B ))
Os resultados das operações do Exemplo 13 seriam, nesta ordem, 75 (52
+ 23), com A assumindo esse valor. Na sequência, subtrai-se o valor de B e
armazena-se em A (75-23), e A retorna para o valor 52. Em seguida,
A é multiplicado por B (52*23) e armazena o valor 1196, mas, na divisão
seguinte, retorna para 52 (1196/23). A tem seus bits comparados por uma
operação AND, resultando em 20 (52 & 23), e, por fim, por uma operação
OR, resultando em 23 (20 | 23).
Assim, apesar de o Shell Script tratar todos os dados de forma textual e
não apresentar uma tipagem forte de dados, operações aritméticas e lógicas
são possíveis desde que realizadas entre duplos parênteses para sinalizar ao
interpretador a utilização desse tipo de operação.
As variáveis especiais utilizadas como parâmetros posicionais dão acesso
aos argumentos passados para funções e comandos por meio das variáveis
numeradas do $1 em diante, ou, ainda, com a variável $@, que dá acesso a
todos os argumentos. O estado de saída, por sua vez, é acessível pela variável
$?. Com essas variáveis especiais, é permitida ainda a troca de dados entre
scripts diferentes. Por fim, as variáveis especiais $! e $$ garantem acesso
ao número de identificação de processos.
15Tipos de dados em Shell Script Linux
ALBING, C.; VOSSEN, J. P. bash cookbook: solutions and examples for bash users. Sebas-
topol: O’Reilly, 2017. 726 p.
BLUM, R. Linux command line and shell scripting. Indianapolis: Wiley, 2008. 840 p.
NEWHAM, C. Learning the bash shell: Unix shell programming. 3. ed. Sebastopol: O’Reilly,
2005. 352 p.
ROBBINS, A.; BEEBE, N. H. F. Classic shell scripting: automate your Unix tasks. 3. ed.
Sebastopol: O’Reilly, 2005. 558 p.
Leituras recomendadas
COSTA, D. G. Administração de redes com scripts: Bash Script, Python e VBScript. 2. ed.
Rio de Janeiro: Brasport, 2010. 172 p.
JARGAS, A. M. Shell script professional. São Paulo: Novatec, 2008. 480 p.
MANZANO, J. A. M. G.; OLIVEIRA, J. F. Algoritmos: lógica para desenvolvimento de
programação de computadores. 29. ed. São Paulo: Érica, 2019. 368 p.
TAYLOR, D.; PERRY, B. Wicked cool shell scripts: 101 scripts for Linux, OS X, and Unix
systems. 2. ed. San Francisco: No Starch Press, 2016. 400 p
Tipos de dados em Shell Script Linux16