Mo Budlong, Unix Insider, 01/09/1999
Certa vez, há muito tempo atrás, o Unix possuia apenas um shell, o Bourne shell, e quando um script era escrito, o shell lia o script e executava os comandos. Então outro shell apareceu, e depois, outro. Cada shell possuia sua própria sintaxe e alguns, como o C shell, eram bastante diferentes do original. Isto significava que, se um script usava os recursos de um shell ou de outro, ele deveria ser executado usando aquele shell. Em vez de escrever:
doit
O usuáiro tinha que escrever:
/bin/ksh doit
ou:
/bin/csh doit
Para remediar esta situação, uma alteração inteligente foi feita no kernel Unix -- agora um script poderia ser escrito começando com uma combinação hash-bang (#!) na primeira linha, seguida pelo shell que executaria o script. Por exemplo, dê uma olhada no seguinte script, chamado doit:
#!/bin/ksh # # do some script here #
Neste exemplo, o kernel lê o script doit, vê o hash-bang, e continua a ler o resto da linha, onde ele encontra /bin/ksh. O kernel então inicia o Korn shell com doit como um dos argumentos, e passa a ele o script, como se o seguinte comando tivesse sido escrito:
/bin/ksh doit
Quandi o /bin/ksh começa a ler o script, ele vê o hash-bang na primeira linha como um comentário (por que ele começa com um hash), e ignora o mesmo. Para ser executado, o path completo do shel é necessário, já que o kernel não irá examinar sua variável PATH. O manipulador de hash-bang do kernel faz mais que só executar um shell alternativo, ele realmenet pega os argumentos que seguem o hash-bang e usa os mesmos como um comando, e acrescente o nome do arquivo como argumento àquele comando.
Você pode iniciar um script Perl, chamado doperl, usando o hash-bang:
#!/bin/perl # do some perl script here
Se você escrever doperl, o kernel examina o hash-bang, extrai o comando /bin/perl, e executa o mesmo como se você tivesse escrito:
/bin/perl doperl
Existem dois mecanismos em funcionamento que permitem que isto funcione. O primeiro é a interpretação do kernel do hash-bang, o segundo é que o Perl vê a primeira linha como um comentário e ignora a mesma. Esta técnica não irá funcionar com linguagens de script que não tratam linhas que começam com um hash como comentário -- nestes casos, provavelmente você terá um erro. Você não precisa se limitar a usar este método apenas para executar scripts, apesar que é onde ele é mais útil.
O seguitne script, chamado helpme, apresenta a si mesmo no terminal quando você executa o comando helpme:
#!/bin/cat vi unix editor man manual pages sh Bourne Shell ksh Korn Shell csh C Shell bash Bourne Again Shell
Este truque do kernel irá executar um argumento após o nome do comando. Para esconder a primeria linha, faça que o arquivo use o more, iniciando na segunda linha, mas certifique-se de usar o path correto:
#!/bin/more +2 vi unix editor man manual pages sh Bourne Shell ksh Korn Shell csh C Shell bash Bourne Again Shell
Ao escrever o helpme como um comando, o kernel converte isto para:
/bin/more +2 helpme
Tudo a partir da linha dois em diante é mostrado:
helpme vi unix editor man manual pages sh Bourne Shell ksh Korn Shell csh C Shell bash Bourne Again Shell etc.
Você pode usar esta técnica para criar scripts aparentemente inúteis, como um arquivo que remove a si mesmo:
#!/bin/rm
Se você der o nome de flagged a este script, a execução do mesmo irá fazer com que o comando seja executado como se você tivesse escrito:
/bin/rm flagged
Você pode usar isto em um script para indicar que você está executando alguma coisa, então execute o script para remover o mesmo:
#!/bin/ksh # first refuse to run if the flagged file exists if [ -f flagged ] then exit fi # create de thalg file echo #! /bin/rm" > flagged chmod a+x flagged # do some logic here # unflag the process by executing the flag file flagged
Antes que você comece a executar comandos longos com esta técnica, tenha em mente que os sistemas geralmente tem um limite superior (tipicamente 32 caracteres) no comprimento do código na linha #!.
Quando você escreve um shell script, os argumentos são normalmente necessários para que o script funcione corretamente. Para garantir que os argumentos façam algum sentido, é geralmente necessário validar os mesmos.
Testar para ver se há argumentos suficientes é geralmente o método mais fácil de validação. por exemplo, se você criou um script shell que pede dois nomes de arquivos para operar, teste a existência de dois argumentos na linha de comando. para fazer isto no Bourne e no Korn shell, verifique o valor de $# -- uma variável que contém a contagem de argumentos, além do próprio comando. É também uma boa pratica incluir uma mensagem que detalhe as razões por que o comando falhou. Isto é criado em uma função usage.
O script twofiles abaixo, testa se há dois argumentos na linha de comando:
#!/bin/ksh # twofile script handles two files named on the command line # a usage function to display help for the hapless user usage () { echo "twofiles" echo "usage: twofiles file1 file2" echo "Processes two files" } # test if we have two arguments on the command line if [ $# != 2 ] then usage exit fi
Uma prática mais segura é validar o máximo que você puder antes de executar alguma coisa. A seguinte versão de twofiles verifica a contagem de argumentos e testa os dois arquivos. Se o arquivo 1 não existe ( if [ ! -f $1 ]) uma mensagem de erro é configurada, uma mensagem de uso é apresentada, e o programa termina. O mesmo é feito para o arquivo 2:
#!/bin/ksh # twofiles script handles two files named on the command line # a usage function to display help for the hapless user # plus an additional error message if it has been filled in usage () { echo "twofiles" echo "usage: twofiles file1 file2" echo "Processes two files" echo " " echo $errmsg } # test if we have two arguments on the command line if [ $# != 2 ] then usage exit fi # test if file one exists and send an additional error message # to usage if not found if [ ! -f $1 ] then errmsg=${1}": File Not Found" usage exit fi # same for file two if [ ! -f $2 ] then errmsg=${2}": File Not Found" usage exit fi # we are ok at this point so continue processing here
Note que no Korn shell você pode usar a sintaxe de teste de colchetes duplos, que é mais rápida. O colchete simples na verdade chama um programa test para testar os valores, enquanto que com o colchete duplo o teste é implementado no Korn shell e não precisa chamar um programa separado.
O teste de colchete duplo não funciona no Bourne shell:
if [[ $# != 2 ]]
ou
if [[ ! -f $1 ]]
ou
if [[ ! -f $2 ]]
Esta validação pode evitar erros posteriores na lógica do programa quando subitamente percebe-se que um arquivo está faltando. Considere isto como uma boa prática de programação.
Mo Budlong, o presidente da King Computer Services, especializado em Web Linux/Unix e desenvolvimento cliente/servidor, e atualmente está trabalhando na conversão de aplicações do Windows para o Linux. Ele publicou livros e artigos em assuntos que variam da linguagem Assembly a World Wide Web, e é o autor do best-seller Teach Yourself COBOL in 21 Days, agora em sua terceira edição. Ele está trabalhando atualmente em um livro sobre o básico do Unix.