Shell Script

Shell é a linha de comandos de Linux e UNIX, é ela que interpreta todos os comandos inseridos pelo utilizador. Para além de executar comandos do sistema esta também tem comandos de programação tais como if, for, while, variáveis e também funções, permitindo desta forma criar chamadas de comandos mais flexíveis.

Shell script é basicamente um ficheiro com uma determinada sequência de comandos shell, estes scripts podem ser executados de diversas formas podemos criar o nosso script e executá-lo usando os comandos sh ou bash.

sh Script.sh

ou

bash Script.sh

Ambos executam o script, com uma diferença, o sh é o interpretador standard de comandos Shell, por sua vez o bash é o interpretador de comandos Shell tal como o sh, mas com mais algumas funcionalidades, nomeadamente o suporte de variáveis do tipo array, select, read, etc… Por esse motivo vamos usar o bash.

Uma outra forma de executar o nosso script é tornando-o executável. Para isso na primeira linha do nosso script colocamos o caminho para o interpretador, por exemplo:

#!/bin/bash
printf “Hello World”

Em seguida executamos o comando

chmod +x Script.sh

para tornar o nosso script executável e depois basta corrê-lo.

Vamos agora passar à prática, começando por ver como definir variáveis para o nosso Shell Script. A declaração de variáveis é bastante simples, basta colocar o nome=valor sem espaços. Vamos ver vários exemplos de declaração de variáveis.

#!/bin/bash

Nome="White Magician";
NUMERO=70101;
_ID1=1;
_id2="ABFISOEEQS";
 
echo $Nome
echo $NUMERO
echo $_ID1;
echo $_id2;

Como podemos ver as variáveis podem ter nomes com letras de a..z e A..Z, números e “_”. Embora possam conter números estes não podem ser colocados no início, pois variáveis iniciadas com um número estão reservadas para a Shell. O uso de ; não é obrigatório como podemos ver, mas existem casos em que o seu uso faz parte da sintaxe. Veremos esses casos mais à frente. No exemplo para aceder ao valor guardado numa variável usamos o prefixo $.

As variáveis podem aí ser de valor constante, ou seja, o seu valor não pode ser alterado, para isso usamos o comando readonly como podemos ver em seguida.

#!/bin/bash
 
var=1000;
readonly var;
readonly var2=12;
var=9;

Ao executar este script ele irá retornar um erro dizendo que a variável var é apenas de leitura. Podemos declarar a variável e em seguida declará-la como readonly ou então fazer os dois passos de uma vez como podemos ver.

As variáveis podem aí ser eliminadas, ou seja apagadas da lista de variáveis da Shell. Para isso basta usar comando unset, mas este comando apenas funciona em variáveis não declaradas como readonly.

#!/bin/bash

var1=100;
readonly var2=10;
unset var1;
unset var2;

echo $var1;
echo $var2;

Ao executar este script podemos ver duas operações importantes. Primeira, ao fazer echo $var1 não será impresso nenhum valor, visto esta variável já não existir. Segunda, o retorno de um erro devido à tentativa de eliminar uma variável readonly e que ao ser impresso o seu valor foi mantido.

Uma estrutura muito útil para a criação de scripts dinâmicos e mais flexíveis é o array, também disponível na nossa Shell, mas apenas no bash e não no sh. Os arrays podem ser facilmente usados com a seguinte sintaxe nome[índice]=valor. Vamos agora ver o seu funcionamento.

#!/bin/bash

lista[0]=9999;
lista[1]=1111;
lista[10]=333;

echo ${lista[0]};
echo ${lista[1]};
echo ${lista[10]};
echo ${lista[@]};

Aqui podemos ver um pequeno exemplo da utilização de arrays em Shell Script. O índice @ selecciona todos os índices, ou seja, retorna todos os valores guardados no array.

O próximo exemplo mostra algumas das mais usadas variáveis de ambiente da Shell.

#!/bin/bash

echo $PWD 	#Caminho para a directoria actual.
echo $UID 	#ID do utilizador que iniciou a Shell
echo $SHLVL 	#Numero de sessões Shell abertas.
echo $REPLY 	#Contém o último input recebido pela função read não suportado pelo “SH”
echo $RANDOM 	#Cria um número aleatório entre 0 e 32767 não suportado pelo “SH”
echo $PATH 	#Caminhos de pesquisa para comandos das Shell.
echo $HOME 	#Caminho para a HOME do utilizador actual.

Ainda no âmbito das variáveis é-nos ainda possível aceder a variáveis especiais. Podemos ver uma pequeno exemplo do uso dessas variáveis:

#!/bin/bash

echo $0		#Nome do Script.
echo $1		#Valor do primeiro argumento do Script.
echo $2		#Valor do segundo argumento do Script.
echo $#		#Numero de argumentos do Script.
echo $@		#Todos os valores dado ao Script.
echo $$ 	#Número do processo do Script.
echo $! 	#Número do último comando em  background.
echo $-         #Todas as opções passadas ao script

Vamos agora ver uma alternativa ao comando echo para imprimir dados. O comando printf permite, à semelhança do comando echo, imprimir dados com a vantagem de que consegue fazê-lo de forma formatada o seu funcionamento é praticamente igual ao printf da linguagem C/C++. Vamos ver então alguns exemplo do nosso printf.

#!/bin/bash

printf "Olá %s bem vindo a %s\n" $USER $HOME
printf "Basta colocar o texto entre \"\" \n"
printf "E em seguida as variáveis separadas por um espaço!\n"

Como podemos ver é bastante simples usar o comando printf. É de referir que a ordem pela qual as variáveis são colocadas será a mesma na altura da impressão ou seja colocar $USER $HOME tem um resultado diferente de colocar $HOME $USER.

Algo muito importante para o nosso código são os comentários em Shell Script, que podem ser feitos com o símbolo #. Este carácter indica que toda a linha a partir do carácter deve ser ignorada pelo bash. Mas como já devem ter reparado os nossos scripts começam com #!/bin/bash, que é um caso especial esse comentário é usado para indicar qual a shell que deve ser usada para interpretar o script no nosso caso a bash, esta linha deve ser a primeira do nosso script caso contrário será interpretada como um comentário e ignorada pelo interpretador. Vamos agora ver alguns exemplos simples de comentários.

#!/bin/bash

#Todo o texto aqui escrito não será impresso.
printf “Podemos ainda comentar ...” # apenas parte da linha

Infelizmente os comentários de Shell Script não permitem o comentário em bloco por isso apenas podemos comentar um linha na totalidade ou parte dela, indicando o início do comentário mas não o seu fim na linha.

Já sabemos como imprimir dados vamos agora ver como pedir dados ao utilizador. Para isso temos o comando read, que permite ler o input do utilizador vejamos um pequeno exemplo prático.

#!/bin/bash

printf “Utilizador : ”;
read usr;
printf “Password : ”;
read pass;

printf “%s a sua password é %s\n” $usr $pass;

Passemos agora a estruturas condicionais, Shell Script dispõe de estruturas como if e else, existente em praticamente todas as linguagens de programação, bem como o case (também conhecido por switch noutras linguagens de programação). Vamos ver um exemplo da sua utilização. Comecemos pelo case.

#!/bin/bash

read USER;

case “$USER” in
    magician) printf “Magician seja bem vindo.\n”;;
    root) printf “Bem vindo ao painel de Admin.\n”;;
    *) printf “Utilizador não reconhecido\n”;;
esac;

Como podemos ver a utilização do case é bastante simples. Damos uma variável e várias opções, dependendo do valor da variável o resultado será diferente. A opção * serve como um default para quando todas as outras falham. Na estrutura if else iremos usar um outro comando, o test. Este comando permite fazer testes booleanos em ficheiros, strings e números. Mas vamos analisar este comando após o if que vamos ver agora.

#!/bin/bash

read usr;

if test $usr = “magician”; 
then
    printf “Bem vindo Magician\n”;
else
    printf “%s não reconhecido!\n” $usr;
fi

O comando test, como podemos ver, realiza testes entre dois valores e tem várias opções. Vamos ver todas as opções que temos, comecemos então pelas opções em ficheiros.

Opções de teste em Ficheiros

-b FILE True se o ficheiro existe e é um ficheiro bloco especial.
-c FILE True se o ficheiro existe e é um ficheiro de caracteres especiais.
-d FILE True se o ficheiro existe e é um directório.
-e FILE True se o ficheiro existe.
-f FILE True se o ficheiro existe e é um ficheiros regular.
-g FILE True se o ficheiro existe e contém o seu SGID.
-h FILE True se o ficheiro existe e é um link simbólico.
-k FILE True se o ficheiro existe e contém "sticky" bit set.
-p FILE True se o ficheiro existe e é um named pipe.
-r FILE True se o ficheiro existe e permite a sua leitura.
-s FILE True se o ficheiro existe e o seu tamanho é maior que zero.
-u FILE True se o ficheiro existe e contém o seu SUID.
-w FILE True se o ficheiro existe e permite ser escrito.
-x FILE True se o ficheiro existe e é executável.
-O FILE True se o ficheiro existe e o seu dono é o utilizar corrente.

Opções de teste em Strings

-z string          True se a String tem tamanho igual a zero.
-n string          True se a String tem tamanho diferente de zero.
string1 = string2  True se as duas Strings são iguais.
string1 != string2 True se as duas Strings são diferentes.

Opções de teste em números

int1 -eq int2 True se int1 é igual a int2.
int1 -ne int2 True se int1 não é igual a int2.
int1 -lt int2 True se int1 é menor que int2.
int1 -le int2 True se int1 é menor ou igual a int2.
int1 -gt int2 True se int1 é maior que int2.
int1 -ge int2 True se int1 é maior ou igual a int2.

Opções em expressões

! expr         True se expr é false.
expr1 -a expr2 True se expr1 e expr2 são ambas true.
expr1 -o expr2 True se expr1 ou expr2 é true.

Passemos agora aos ciclos Shell Script dispõem, nomeadamente os for e while. Comecemos pelo while com um exemplo simples da sua utilização.

#!/bin/bash

x=0;

while [$x -lt 10]
do
    echo $x;
    x=`expr $x + 1`
done

Algo que pode parecer estranho é sem duvida a linha x=`expr $x + 1`. Basicamente o que tudo isto faz é incrementar um valor à variável x, ela envia a expressão $x+1 para o comando expr que processa a expressão matemática e retorna uma valor numérico. O comando deve ser colocado entre `` para dizer ao interpretador que deve executar a expressão e aguardar o valor retornado.

Temos agora o for. Este ciclo é bastante simples e menos dinâmico que o while, basicamente o for percorre uma sequência de valores e coloca cada um dos valores numa variável temporária que muda de valor a cada ciclo.

#!/bin/bash

for i in 1 9 2 4 3 5 7
do
    echo $i
done

Vamos agora ver como criar funções em Shell Script. A declaração de funções é bastante simples, basta colocar o nome da função seguido de () e um bloco limitado por {}, passemos a um exemplo.

#!/bin/bash

mg="Magician";
 
imprime(){
    printf "Olá %s\n" $mg;
}
 
imprime;

As funções, ao contrário da maioria das linguagens de programação, em Shell Script não são chamadas sob a forma imprime(), mas apenas com o nome da função sem o par de parêntesis.

Para terminar o nosso artigo irei mostrar como redireccionar o input/output dos nossos scrips com Shell Script. É possível passar prints para ficheiros e o conteúdo de ficheiros para outros ficheiros até mesmo para variáveis do nosso script.

#!/bin/bash

Text1="Este texto será gravado dentro do ficheiro texto1.txt";

echo $Text1 > texto1.txt;

Text2="Este texto será concatenado ao texto já existente no ficheiro texto1.txt";

echo $Text2 >> texto1.txt

Como podemos ver, é possível redireccionar o output de variáveis do nosso script para ficheiro usando um símbolo >, que apaga todo o conteúdo do ficheiro e insere o valor enviado. Também se podem usar os símbolos >>, que adiciona o valor enviado ao já existente no ficheiro. Em ambos os casos se o ficheiro não existir ele é criado.

Espero que tenham gostado do artigo, a partir deste momento têm o conhecimento básico sobre Shell Script que permite a criação de scripts para as mais diversas tarefas bastando adaptar as bases às necessidades.

Publicado na edição 12 (PDF) da Revista PROGRAMAR.