Estrutura geral de um Script Shell PDF Imprimir E-mail
Escrito por Prof. Carlos A. Maziero   
Ter, 25 de Janeiro de 2011 01:26

Os arquivos de script permitem construir esquemas de execução complexos a partir dos comandos básicos do shell. A forma mais elementar de arquivo de script é apenas um conjunto de comandos em um arquivo texto, com permissões de execução habilitadas. O arquivo backup, cujo conteúdo é mostrado a seguir, é um exemplo de script:

echo "Iniciando backup..."

# montar o diretório do servidor de backup
mount backserver.ppgia.pucpr.br:/backup /backup

# efetuar o backup em um arquivo tar compactado
tar czf /backup/home.tar.gz /home

# desmontar o diretório do servidor de backup
umount /backup

echo "Backup concluido !"

Quando o script backup for executado, os comandos do arquivo serão executados em seqüência pelo shell corrente (de onde ele foi lançado). Assim, se o usuário estiver usando o shell bash, os comandos do script serão executados por esse shell. Como isso poderia gerar problemas em scripts usados por vários usuários, é possível forçar a execução do script com um shell específico (ou outro programa que interprete os comandos do arquivo). Para isso é necessário informar ao sistema operacional o programa a ser usado, na primeira linha do arquivo do script:

#!/bin/bash --noprofile

# A opção --noprofile inibe a leitura dos arquivos de inicialização
# do shell, tornando o lançamento do script muito mais rápido.
# comandos de um script em Bash-Shell

server=backserver.ppgia.pucpr.br
backdir=/backup
...
exit 0

Com isso, será lançado um shell Bash separado (um novo processo), somente para interpretar as instruções do script. O novo processo será terminado pelo comando exit, cujo parâmetro é devolvido ao shell anterior através da variável $?. Esse procedimento pode ser usado para lançar scripts para outros shells, ou mesmo outras linguagens interpretadas, como Perl, Awk, Sed, Php, Python, etc.

Parâmetros de entrada
Os argumentos da linha de comando são passados para o shell através da variável local $argv. Os campos individuais dessa variável podem ser acessados como em uma variável local qualquer. Além disso, uma série de atalhos é definida para facilitar o acesso a esses parâmetros:

$0 : o nome do script
$n : o n-ésimo argumento da linha de comando
$* : todos os argumentos da linha de comando
$# : número de argumentos
$? : status do último comando executado (status <> 0 indica erro)
$$ : número de processo (PID) do shell que executa o script
Eis um exemplo através do script listaparams:

#!/bin/bash 
# exemplo de uso dos parâmetros de entrada
echo "Nome do script : $0"
echo "Primeiro parâmetro : $1"
echo "Todos os parâmetros : $*"
echo "Numero de parametros : $#"
echo "Numero deste processo : $$"
exit 0

Chamando o script acima com alguns parâmetros se obtém a seguinte resposta:

~> listaparams banana tomate pessego melao pera uva
Nome do script : listaparams
Primeiro parâmetro : banana
Todos os parâmetros : banana tomate pessego melao pera uva
Numero de parametros : 6
Numero deste processo : 2215
~>

Controle de fluxo


Existem diversos construtores de controle de fluxo que podem ser usados em scripts BASH-Shell. Os principais são descritos a seguir.

Condições


Como na maioria das linguagens, no shell Bash, testes de condições são realizados por estruturas do tipo if-then-else. As condições testadas são os status de saída da execução de comandos (o valor inteiro retornado pela chamada de sistema exit() do comando). Caso o status seja zero (0), a condição é considerada verdadeira:


if cmp $file1 $file2 >/dev/null   # testa o status do comando cmp
then
   echo "os arquivos são iguais"
else
   echo "os arquivos são distintos"
fi

Essa lógica “ao contrário” pode causar uma certa confusão aos iniciantes. Assim, para simplificar a programação de scripts, é definido um operador test condition, que também pode ser representado por [ condition ] e retorna zero (0) se a condição testada for verdadeira:

if [ $n1 -lt $n2 ]          # $n1 é menor que $n2?
then
   echo "$n1 é menor que $n2"
fi

if test $n1 -lt $n2         # $n1 é menor que $n2?
then
   echo "$n1 é menor que $n2"
fi

Os principais operadores de teste disponíveis são:

Operador if-then

if comando
then
   ...
fi

# testa o status do comando cmp
if cmp file1 file2 >/dev/null
then
   echo "Os arquivos são iguais"
fi
Operador if-then-else

if comando
then
   ...
else
   ...
fi

# testa a existência de $file1
if [ -e "$file1" ]
then
   echo "$file1 existe"
else
   echo "$file1 não existe"
fi
Operador if-then-elif-else

if comando 1
then
   ...
elif comando 2
then
   ...
else
   ...
fi

# compara as variáveis $n1 e $n2
if [ $n1 -lt $n2 ]
then
   echo "$n1 < $n2"
elif [ $n1 -gt $n2 ]
then
   echo "$n1 > $n2"
else
   echo "$n1 = $n2"
fi
Operador case

case variável in
   "string1")
      ...
      break;;
   "string2")
      ...
      break;;
   *):
      ...
      break;;
esac

case $opt in
   "-c") complete=1 ;;
   "-s")
         short=1 ;
         name="" ;;
   *)
         echo "opção $opt desconhecida" ;
         exit 1 ;;
esac 

 
Os principais tipos de teste disponíveis são:

Comparações entre números

-eq : igual a
-ne : diferente de
-gt : maior que
-ge : maior ou igual a
-lt : menor que
-le : menor ou igual a
-a : AND binário (bit a bit)
-o : OR binário (bit a bit)

Comparações entre strings usando []
= : igual a
!= : diferente de
-z : string de tamanho zero
Comparações entre strings usando [[]]
? : menor ou igual a (lexicográfico)
>= : maior ou igual a (lexicográfico)
Associações entre condições
&& : AND lógico
|| : OR lógico

Os operadores de teste em arquivos permitem verificar propriedades de entradas no sistema de arquivos. Eles são usados na forma -op, onde op corresponde ao teste desejado. Os principais testes são:

e : a entrada existe
r : a entrada pode ser lida
w : a entrada pode ser escrita
O : o usuário é o proprietário da entrada
s : tem tamanho maior que zero
f : é um arquivo normal
d : é um diretório
L : é um link simbólico
b : é um dispositivo orientado a bloco
c : é um dispositivo orientado a caracatere
p : é um named pipe (fifo)
S : é um socket special file
u : tem o bit SUID habilitado
g : tem o bit SGID habilitado
G : grupo da entrada é o mesmo do proprietário
k : o stick bit está habilitado
x : a entrada pode ser executada
nt : Verifica se um arquivo é mais novo que outro
ot : Verifica se um arquivo é mais velho que outro
ef : Verifica se é o mesmo arquivo (link)
Eis um exemplo de uso de testes em arquivos:

arquivo='/etc/passwd'

if [ -e $arquivo ] 
then
   if [ -f $arquivo ]
   then
      if [ -r $arquivo ]
      then
         source $arquivo
      else
         echo "Nao posso ler o arquivo $arquivo"
      fi
   else
      echo "$arquivo não é um arquivo normal"
   fi
else
   echo "$arquivo não existe"
fi
Laços
Laço for

for variável in lista de valores
do
   ...
done

for i in *.c
do
   echo "compilando $i"
   cc -c $i
done
Laço while

while condição
do
   ...
done

i=0
while [ $i -lt 10 ]
do
   echo $i
   let i++
done
Operador select

select variável in lista de valores
do
   ...
done

select f in "abacate" "pera" "uva" "banana" "morango"
do
   echo "Escolheu $f"
done


Além das estruturas acima, algumas outras podem ser usadas para executar comandos em situações específicas:

`comando` : substitui a expressão entre crases pelo resultado (stdout) da execução do comando. Por exemplo, a linha de comando abaixo coloca na variável arqs os nomes de arquivos retornados pelo comando find:
arqs=`find /etc -type f -iname '???'`
comando1; comando2; comando3 : executa seqüencialmente os comandos indicados
Operadores aritméticos
Variáveis contendo números inteiros podem ser usadas em expressões aritméticas e lógicas. A atribuição do resultado de uma expressão aritmética a uma variável pode ser feita de diversas formas. Por exemplo, as três expressões a seguir têm o mesmo efeito:

i=$((j + k))

let i=j+k

i=`expr $j + $k`
Os principais operadores aritméticos disponíveis são:

+ - * / : aritmética básica
** : potenciação
% : módulo (resto)
+= -= *= /= %= : aritmética e atribuição (como em C)
« » : deslocamento de bits
«= »= : deslocamento e atribuição
& | : AND e OR binários
&= |= : AND e OR binários com atribuição
! : NOT binário
^ : XOR binário
&& || : AND e OR lógicos
Exercícios
Analise e descreva o que faz o script abaixo, passo a passo. Em seguida, copie-o no arquivo meuscript, em sua área de trabalho, e teste-o.

#!/bin/bash --noprofile 
 
# testar se ha um so parametro de entrada
if [ $# != 1 ]
then
   echo ''Erro na chamada''
   echo ''Uso: criadir numero de diretorios''
   exit 1
fi
 
num=0
 
while [ $num -lt $1 ]
do
   echo ''Criando diretorio $num''
   mkdir dir$num
   let num++
done
 
echo ''Acabei de criar $1 diretorios''

exit 0


Escreva um script chamado clean para limpar seu diretório $HOME, removendo todos os arquivos com extensão bak ou ~ que não tenham sido acessados há pelo menos 3 dias. Dica: use os comandos find e rm e a avaliação por aspas inversas.

Escreva um script para criar diretórios com nome DirXXX, onde XXX varia de 001 a 299. Dica: use o comando printf para gerar o nome dos diretórios a criar.

Escreva um conjunto de scripts para gerenciar o apagamento de arquivos. O script del deve mover os arquivos passados como parâmetros para um diretório lixeira; o script undel deve mover arquivos da lixeira para o diretório corrente e o script lsdel deve listar o conteúdo da lixeira. O diretório lixeira deve ser definido através da variável de ambiente $LIXEIRA.

Funda os scripts do exercício anterior em um só script del, com os demais (undel e lsdel) sendo links simbólicos para o primeiro. Como fazer para que o script saiba qual a operação desejada quando ele for chamado, sem precisar informá-lo via parâmetros?

Escreva um script para verificar quais hosts de uma determinada rede IP estão ativos. Para testar se um host está ativo, use o comando ping. A rede deve ser informada via linha de comando, no formato x.y.z, e o resultado deve ser enviado para um arquivo com o nome x.y.z.log. Deve ser testada a acessibilidade dos hosts de x.y.z.1 a x.y.z.254.

Última atualização em Ter, 25 de Janeiro de 2011 01:47
 

Adicionar comentário


Código de segurança
Atualizar