Shell Script: Programação Simplificada – Parte I
Conheça as características e funcionalidades de cada Shell
Programar em linguagem Shell é algo muito comum para profissionais que atuam na área de Banco de Dados (DBA), Administradores de Sistemas Operacionais UNIX/LINUX (SysAdmin) e outros que necessitem automatizar ou executar tarefas específicas através de scripts previamente escritos.
A linguagem Shell, assim como qualquer outra linguagem de programação, possui uma série de regras e controles que devem ser definidas pelo programador antes, durante e ao término de cada programa.
O que é o Shell?
Sistemas UNIX/Linux são desenhados para ter o Kernel como centro de todas as atividades. O Kernel é responsável pela comunicação entre o Sistema Operacional e dispositivos externos, bem como tarefas e processos.
Usuários normais por outro lado, não interagem diretamente com o Kernel. Essa interação é feita através de um Shell. O Shell é um interpretador de comandos que também pode gerenciar outros programas e permitir a criação de scripts para automatizar diversas tarefas do sistema.
Existem vários tipos de Shell disponíveis na maioria das distribuições Unix/Linux, entre eles:
Bourne Shell (sh)
Conhecido como “sh” este Shell substituiu o anterior Thompson Shell (Conhecido também como “sh”) incorporando novas funcionalidades. Foi desenvolvido por Stephen Born e lançado em 1977. O Executável deste Shell fica localizado em “/bin/sh” em distribuições UNIX. Algumas Características:
- Shell com mais portabilidade para programação (Shell Script).
- Linguagem baseada em Algol.
- Possui histórico de comandos, edição e aliases.
- Usa o símbolo $ como prompt default.
- Parte do Unix; Não disponível em Linux.
C Shell (csh)
Este também é um Shell desenvolvido a partir da versão Thompson Shell (antecessora da versão Bourne Shell) . Sua sintaxe é modelada segundo a linguagem de programação C, com estruturas de controle e comandos semelhantes. Possui algumas melhorias em relação ao Bourne Shell tais como aliases e histórico de comandos. Foi desenvolvido por Bill Joy. Algumas Características:
- Não compatível com scripts Bourne Shell.
- Linguagem baseada em C.
- Possui histórico de comandos, auto-completar, programação (scripting), aliases e controle de Jobs.
- Usa o símbolo % como prompt default.
Korn Shell (ksh)
Um dos mais populares. É uma derivação do Bourne Shell (bsh) e do C Shell (csh). Possui a maioria das suas funcionalidades de ambos incluindo outras novas como interação con outras linguages como awk, icon, perl e tcl. Foi desenvolvido por David G. Korn e vem sido muito utilizado desde 1982. Algumas Características:
- Compatível com scripts Bourne Shell.
- Certificado como Open Source (OSI)
- Possui histórico de comandos, auto-completar, programação (scripting), aliases e controle de Jobs.
- Inclui estilo “emacs” como alternativa para o CSH e POSIX.
- Por muitos anos foi exclusivo de uso em UNIX devido a licenciamento.
- Atualmente encontrado em várias distribuições Linux (Open Source).
Bourne-Again Shell (bash)
Este é o Shell mais conhecido atualmente no mercado. Desenvolvido com apelo de distribuição FREE (GNU Free Software Foundation), se tornou padrão na maioria das distribuições Linux atuais como Red Hat, Suse, Oracle Linux entre outras. O BASH possui a maioria das funcionalidades do C Shell e do Korn Shell. Trabalha em conformidade com POSIX e padrões de ferramentas Shell. O BASH ainda oferece diversas melhorias tanto para programação como para uso interativo, tais como:
- Edição de Linha de Comando.
- Histórico de Comandos ilimitado.
- Controle de Jobs e Tarefas Agendadas.
- Funções Shell e Criação de Alias.
- Matrizes Indexadas ilimitadas.
- Operações Aritméticas.
- Programação e personalização.
- Compatibilidade com scripts Bourne Shell.
- Executável /bin/bash.
Shell alternativo
A lista anterior fornecida é sem dúvida a mais comum encontrada no mercado. Existem vários outros Shell’s disponíveis e podem ser dividos em 2 (duas) categorias: Open Source (Alternativos ao Shell proprietário) e Shell especializado. Alguns Shell especializados são: tcsh, pdksh e zsh.
Enhanced C Shell (tcsh)
Ao contrário do que se vê normalmente, a abreviação tsch “The Enhanced C Shell” o “t” na verdade vem de TENEX (sistema operacional que inspirou a utilização do “auto-completar” compatível com o C Shell. Algumas Características:
- Compatível com Scripts C Shell.
- Possui edição de comandos e correção ortográfica.
- Auto-Completar corrigido e melhor em relação ao csh.
- Licenciamento Open Source.
Public Domain Korn Shell (pdksh)
Enquanto o Korn Shell é mantido como proprietário em plataformas UNIX, o Public Domain Korn Shell foi criado como alternativa de compatibilidade para:
- Scripts ksh88.
- Software Open Source (public domain).
Z Shell (zsh)
Inclui a maioria dos recursos do Bourne-Again Shell, Korn Shell e Enhanced C Shell. Inclui novas funcionalidades próprias:
- Pode ser executado no Korn ou Bourne Shell em modo de compatibilidade.
- Um dos Shell com mais compatibilidade e funcionalidades.
- Free. Open Source.
Arquivos de configuração do Shell
Quando um novo Shell é iniciado, o mesmo lê alguns arquivos de configuração que configuram o ambiente para o Shell que será executado. Entender os arquivos de configuração do Bourne Shell é muito importante, uma vez que a maioria dos outros Shells mantém compatibilidade com o Bourne Shell e lê seus arquivos de configuração, se os mesmos estiverem presentes. O Bourne Shell mantém suas configurações em 2 (dois) arquivos. Estes arquivos são utilizados por todos os Shells, uma vez que não exista o arquivo específico de cada Shell no diretório $HOME. A configuração do ambiente (Sistema) é mantida no arquivo /etc/profile. Algumas configurações de ambiente (sistema):
Path default onde estão localizados os programas executáveis.
Configurações default de prompt.
Limites para sessão de Usuários (ulimit)
Para facilitar que outros software alterem de maneira segura o arquivo de configuração do Shell, o Linux também interpreta scripts encontrados no diretório /etc/profile.d.
Abaixo arquivo /etc/profile no Linux:
for i in /etc/profile.d/*.sh ; do
if [ -r "$i" ]; then
if [ "$PS1" ]; then
. $i
else
. $i >/dev/null 2>&1
fi
fi
done
Listagem 1. Arquivo /etc/profile
Arquivo ˜/.profile
O arquivo de configuração de usuário também é executado, caso exista. Este arquivo fica localizado no home ($HOME) de cada usuário. Ele permite com que os usuários do Sistema Operacional executem customizações de variáveis conforme sua necessidade.
export PERL_HOME=/usr/local/perl
export PERL5LIB=$PERL_HOME/lib
export PATH/usr/bin:/sbin:/usr/sbin
stty erase ˆH
Listagem 2. Arquivo ˜/.profile
No caso do Bourne-Again Shell, o arquivo configuração do Shell para usuários pode ser localizado em $HOME/.bash_profile de cada usuário do S.O.
Canais de Comunicação
Todos os programas escritos em ambiente UNIX / Linux utilizam os canais STDIN, STDOUT e STERR como comunicação com os dispositivos externos. STDIN (ou ‘Standard In’) é utilizado como canal de entrada, onde a informação é enviada a um programa. Os caracteres digitados no teclado de um computador são recebidos por um programa via STDIN.
A informação de saída de um programa utiliza normalmente o STDOUT ou STDERR (ou ambos). Por default, estes dois canais são gerados em tela. A vantagem de utilizar estes dois canais é que pode-se separar a saída normal de programa de seus erros. Nem sempre é interessante ver ambos em uma saída apenas.
O fluxo correto utilizado pelos canais de comunicação consiste em entrada, processamento e saída, conforme figura 1.
Figura 1. Fluxograma de Canais de Comunicação
Redirecionamento para Arquivos
O Redirecionamento de canais de comunicação para arquivos facilita a interpretação dos resultados gerados por um programa e ainda podem garantir um histórico de execução para posterior análise. Os seguintes caracteres são utilizados para redirecionamento:
< |
Redireciona o STDIN de um arquivo |
> |
Redireciona o STDOUTpara um arquivo (sobrescreve) |
>> |
Redireciona o STDOUT para um arquivo (inserção/append) |
2> |
Redireciona o STDERR para um arquivo (sobrescreve) |
2>> |
Redireciona o STDERR para um arquivo (inserção/append) |
&> |
Redireciona ambos STDOUT e STDERR |
Redirecionar o arquivo “/etc/passwd” para STDIN so programa “sort”:
$ sort < /etc/passwd
Listagem 3. Redirecionando STDIN do comando sort
A saída do comando “echo” é redirecionada para o arquivo “salario”. O conteúdo será 342 e todo o conteúdo existente será excluído. Se o arquivo não existir, o mesmo será criado:
$ echo 342 > salario
Listagem 4. Redirecionando STDOUT do comando echo
A saída do comando “ls” será exibida em tela, porém qualquer erro que venha a ocorrer será redirecionado para o arquivo “erros”. Se o arquivo já existir, o mesmo será sobrescrito.
$ ls –alR /proc 2> erros
Listagem 5. Criando arquivo erros com conteudo do comando ls
Praticamente o mesmo caso acima, com a diferença que os possíveis erros gerados pelo comando “find” serão adicionados ao arquivo “erros” e nenhuma informação neste arquivo será perdida. Se o arquivo “erros” não existir, o mesmo será criado.
$ find / –name “teste” 2>> erros
Listagem 6. Incluindo saída no arquivo erros
Utilizando pipe
Como fundamento principal em um sistema Unix / Linux, o pipe envia a saída de um comando qualquer (STDOUT) para a entrada de outro comando (STDIN), incluindo toda a cadeia de comandos. O Símbolo para o pipe é identificado por |. Pode ser muito útil para controlar saídas em telas, com o comando abaixo pode-se listar um diretório qualquer com pausa de tela:
ls –la /etc | more
Listagem 7. Listando conteúdo do diretório /etc com pausa de tela
Uso de STDOUT e STDIN em comandos:
ls –la /proc |sort | wc -l
Listagem 8. Contando e ordenando conteúdo do diretório /proc
1 – O Comando “ls –la /proc” lista o conteúdo do diretório /proc.
2 – O comando “sort” orderna o output.
3 – O Comando “wc –l” conta o número de linhas retornadas.
Expressões Regulares
Utilizar Expressões Regulares é um método muito poderoso para comparar partes específicas de um texto ou variável. Elas devem ser avaliadas via STDIN, via Dispositivo de entrada.
Caracteres especiais de expressões Regulares podem ser simplesmente um comparativo. Ex: a=a, b=b,c=c, etc. Existem alguns outros caracteres especiais como:
t |
tab |
n |
Nova Linha |
r |
Carriage Return (ENTER) |
f |
Form Feed (FORM) |
c |
Caracter de controle |
x |
Caracter em Hexa |
. |
Caracter Único |
Variáveis do Shell
As variáveis de um Shell são utilizadas para determinar todas as variáveis configuradas em uma determinada sessão dentro de um Shell. Através do comando “set” pode-se identificar todas as variáveis determinadas em uma sessão. Um uma sessão comum/interativa de um Shell, essas variáveis podem vir de 3 (três) locais:
1 – Das configurações gerais do Ambiente, quando o Shell é executado.
2 – Definidas pelos arquivos de inicialização do Shell tais como: “/etc/profile”, “~/.bash_profile”, “~/.bashrc”, entre outros.
3 – Definidas manualmente pelo usuário através de uma sessão interativa.
As variáveis do Shell não são necessariamente visíveis aos programas iniciados em um Shell. Abaixo é demonstrado que o valor da variável $IDADE não é visível para um novo Shell. Também mostra o uso to comando “unset” para “destruir” uma variável.
1 $ echo $Shell
2 ksh
3 $ IDADE=42
4 $ echo $IDADE
5 42
6 $ bash
7 bash# echo $IDADE
8 .
9 bash# exit
10 $ echo $IDADE
11 42
12 $ unset IDADE; echo $IDADE
13 .
Listagem 9. Utilizando comando unset
Na linha 6 um novo Shell é iniciado. Na linha 8, nenhum resultado é apresentado. Na linha 9 o mesmo Shell é encerrado. Na linha 13 nenhum resultado é apresentado.
Variáveis do Ambiente
Como comando “export” permite com que uma variável do Shell seja definida como uma variável de ambiente, que pode ser identificada por cada processo iniciado no sistema. A lista de todas as variáveis de ambiente pode ser obtida através do comando “env”.
1 $ echo $Shell
2 ksh
3 $ IDADE=42
4 $ env | grep IDADE
5 $. . . NENHUM RESULTADO . . .
6 $ export IDADE
7 $ env | grep IDADE
8 IDADE=42
9 $ bash
10 bash# echo $IDADE
11 42
Listagem 10. Utilizando comando env
Na linha 9 um novo Shell é iniciado.
As variáveis também podem ser adicionadas ao ambiente através de linha de comando antes da chamada de um programa qualquer. Pode-se definir o idioma como Português/Brasil, o Editor como “vi” e somente então o programa “crontab” (agendador de tarefas do Unix/Linux) é executado:
$ LANG=pt_BR EDITOR=vi crontab –e
Listagem 11. Utilizando várias váriaveis no Shell
Para ignorar uma determinada variável de ambiente na chamada de um programa, pode-se utilizar a opção “-u” do comando “env”. Pode-se iniciar um processo de um cliente SSH que não terá acesso ao processo agente do SSH em execução:
$ env –u SSH_AGENT_PID ssh usuario@servidor1
Listagem 12. Restringindo acessos a processos
Executar o comando “env” com a opção “-i” irá iniciar um comando qualquer sem nenhuma variável de ambiente declarada.
$ env –i telnet servidor2
Listagem 13. Restringindo acessos a processos
Executar o comando “env” com a opção “-i” irá iniciar um comando qualquer sem nenhuma variável de ambiente declarada.
$ env –i telnet servidor2
Referências
- Visão Geral sobre Shell Script http://pt.wikipedia.org/wiki/Shell_script
- Learning the Korn Shell (2002 – 2nd Edition – 434pgs) O’Reilly Media, ISBN-10: 0596001959,Bill Rosenblatt, Arnold Robbins
- Linux Command Line and Shell Scripting Bible, (2011 – 2nd Edition – 840pgs) Wiley, ISBN-10: 1118004426, Richard Blum, Christine Bresnahan
- GNU Operating System http://www.gnu.org/software/bash/