Programação Shell LinuxAqui temos um livro livre e completo sobre ShellOs sedentos do "saber livre" são muito benvindos. |
Comandos Shell Script |
||
Home | Artigos | Agradecimentos | Links Amigos | Comprar o livroChangelogs |
Papo de Botequim - Parte 1Papo de Botequim - Parte 2Papo de Botequim - Parte 3Papo de Botequim - Parte 4Papo de Botequim - Parte 5Papo de Botequim - Parte 6Papo de Botequim - Parte 7Papo de Botequim - Parte 8Papo de Botequim - Parte 9Papo de Botequim - Parte 10Papo de Botequim - Parte 11Tira Gosto |
Papo de Botequim - Parte X- E aê amigo, te dei a maior moleza, né? Um exerciciozinho muito simples... - É mais nos testes que eu fiz, e de acordo com o que você ensinou sobre substituição de parâmetros, achei que deveria fazer outras alterações nas funções que desenvolvemos para torná-las de uso geral como você me disse que todas as funções deveriam ser, quer ver? - Claro né mané, se te pedi para fazer é porque estou afim de te ver aprender, mas peraí, dá um tempo! - Chico! Manda dois, um sem colarinho! - Vai, mostra aí o que você fez. - Bem, além do que você pediu, eu reparei que o programa que chamava a função, teria de ter previamente definidas a linha em que seria dada a mensagem e a quantidade de colunas. O que fiz foi incluir duas linhas - nas quais empreguei substituição de parâmetros - que caso uma destas variáveis não fosse informada, a própria função atribuiria. A linha de mensagem seria três linhas acima do fim da tela e o total de colunas seria obtido pelo comando tput cols. Veja como ficou: $ cat pergunta.func
# A funcao recebe 3 parametros na seguinte ordem:
# $1 - Mensagem a ser dada na tela
# $2 - Valor a ser aceito com resposta default
# $3 - O outro valor aceito
# Supondo que $1=Aceita?, $2=s e $3=n, a linha
# abaixo colocaria em Msg o valor "Aceita? (S/n)"
TotCols=${TotCols:-$(tput cols)} # Se nao estava definido, agora esta
LinhaMesg=${LinhaMesg:-$(($(tput lines)-3))} # Idem
Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)"
TamMsg=${#Msg}
Col=$(((TotCols - TamMsg) / 2)) # Para centrar Msg na linha
tput cup $LinhaMesg $Col
read -n1 -p "$Msg " SN
SN=${SN:-$2} # Se vazia coloca default em SN
SN=$(echo $SN | tr A-Z a-z) # A saida de SN serah em minuscula
tput cup $LinhaMesg $Col; tput el # Apaga msg da tela
- Gostei, você já se antecipou ao que eu ia pedir. Só pra gente encerrar este papo de substituição de parâmetros, repare que a legibilidade está horrorível, mas a performance, isto é, velocidade de execução, está ótima. Como funções são coisas muito pessoais, já que cada um usa as suas, e quase não dão manutenção, eu sempre opto pela performance. - Hoje vamos sair daquela chatura que foi o nosso último papo e vamos voltar à lógica saindo da decoreba, mas volto a te lembrar, tudo que eu te mostrei da outra vez aqui no Boteco do Chico é válido e quebra um galhão, guarde aqueles guardanapos que rabiscamos que, mais cedo ou mais tarde, vão te ser muito úteis. O comando eval- Vou te dar um problema que eu duvido que você resolva:
$ var1=3
$ var2=var1
- Te dei estas duas variáveis, e quero que você me diga como eu posso, só me referindo a - A isso é mole, é só fazer: echo $`echo $var2` - Repare que eu coloquei o echo
- A é? Então execute para ver se está correto. $ echo $`echo $var2`
$var1
- Ué! Que foi que houve? O meu raciocínio me parecia bastante lógico... - O seu raciocínio realmente foi lógico, o problema é que você esqueceu de uma das primeiras coisas que te falei aqui no Boteco e vou repetir. O Shell usa a seguinte ordem para resolver uma linha de comandos:
Desta forma, quando chegou na fase de resolução de variáveis, que como eu disse é anterior à execução, a única variável existente era
Problemas deste tipo são relativamente freqüentes e seriam insolúveis caso não existisse a instrução eval cmd
Onde
Desta forma se executássemos o comando que você propôs colocando o $ eval echo $`echo $var2`
3
Este exemplo também poderia ter sido feito da seguinte maneira: $ eval echo \$$var2
3
Na primeira passada a contrabarra (
Agora vou colocar um comando dentro de
$ var2=ls
Vou executar: $ $var2
10porpag1.sh alo2.sh listamusica logaute.sh
10porpag2.sh confuso listartista mandamsg.func
10porpag3.sh contpal.sh listartista3 monbg.sh
alo1.sh incusu logado
Agora vamos colocar em $ var2='ls $var1'
$ var1='l*'
$ $var2
ls: $var1: No such file or directory
$ eval $var2
listamusica listartista listartista3 logado logaute.sh
Novamente, no tempo de substituição das variáveis,
Uma vez um colega de uma excelente lista sobre Shell Script, colocou uma dúvida: queria fazer um menu que numerasse e listasse todos os arquivos com extensão $ cat fazmenu
#!/bin/bash
#
# Lista numerando os programas com extensão .sh no
# diretório corrente e executa o escolhido pelo operador
#
clear; i=1
printf "%11s\t%s\n\n" Opção Programa
CASE='case $opt in'
for arq in *.sh
do
printf "\t%03d\t%s\n" $i $arq
CASE="$CASE
"$(printf "%03d)\t %s;;" $i $arq)
i=$((i+1))
done
CASE="$CASE
*) . erro;;
esac"
read -n3 -p "Informe a opção desejada: " opt
echo
eval "$CASE"
Parece complicado porque usei muito Vamos executá-lo para ver a saída gerada: $ fazmenu.sh
Opcao Programa
001 10porpag1.sh 002 10porpag2.sh 003 10porpag3.sh 004 alo1.sh 005 alo2.sh 006 contpal.sh 007 fazmenu.sh 008 logaute.sh 009 monbg.sh 010 readpipe.sh 011 redirread.sh Informe a opção desejada:
Neste programa seria interessante darmos uma opção de término, e para isso seria necessário a inclusão de uma linha após o loop de montagem da tela e alterarmos a linha na qual fazemos a atribuição final do valor da variável $ cat fazmenu
#!/bin/bash
#
# Lista numerando os programas com extensão .sh no
# diretório corrente e executa o escolhido pelo operador
#
clear; i=1
printf "%11s\t%s\n\n" Opção Programa
CASE='case $opt in'
for arq in *.sh
do
printf "\t%03d\t%s\n" $i $arq
CASE="$CASE
"$(printf "%03d)\t %s;;" $i $arq)
i=$((i+1))
done
printf "\t%d\t%s\n\n" 999 "Fim do programa" # Linha incluida
CASE="$CASE
999) exit;; # Linha alterada
*) ./erro;;
esac"
read -n3 -p "Informe a opção desejada: " opt
echo
eval "$CASE"
Sinais de ProcessosExiste no Linux uma coisa chamada sinal (signal). Existem diversos sinais que podem ser mandados para (ou gerados por) processos em execução. Vamos de agora em diante dar uma olhadinha nos sinais mandados para os processos e mais à frente vamos dar uma passada rápida pelos sinais gerados por processos. Sinais assassinos
Para mandar um sinal a um processo, usamos normalmente o comando kill -sig PID
Onde
Além destes sinais, existe o famigerado
Enfim, existem mil razões para não usar um O trap não atrapalha
Para fazer a monitoração descrita acima existe o comando trap "cmd1; cmd2; cmdn" S1 S2 ... SN ou trap 'cmd1; cmd2; cmdn' S1 S2 ... SN
Onde os comandos
As aspas (") ou os apóstrofos (') só são necessários caso o
Para entender o uso de aspas (") e apóstrofos (') vamos recorrer a um exemplo que trata um fragmento de um script que faz um ftp -ivn $RemoComp << FimFTP >> /tmp/$$ 2>> /tmp/$$ user $Fulano $Segredo binary get $Arq FimFTP
Repare que, tanto as saídas do dos diálogos do
Caso este trap "rm -f /tmp/$$ ; exit" 0 1 2 3 15
Desta forma, caso houvesse uma interrupção brusca (sinais
Caso na linha de comandos do
Este trap "rm -f /tmp/$$" 0 trap "exit" 1 2 3 15
Assim ao receber um dos sinais o programa terminaria, e ao terminar, geraria um sinal
Note também que o Shell pesquisa a linha de comandos uma vez quanto o
Se você desejasse que a substituição fosse realizada somente quando recebesse o sinal, o comando deveria ser colocado entre apóstrofos (
trap 'rm -f /tmp/$$ ; exit' 0 1 2 3 15
Suponha dois casos: você tem dois scripts que chamaremos de
O comando
Se a linha de comandos do trap "" 2
Especifica que o sinal de interrupção ( trap 2
Se você ignora um sinal, todos os Subshells irão ignorar este sinal. Portanto, se você especifica qual ação deve ser tomada quando receber um sinal, então todos os Subshells irão também tomar a ação quando receberem este sinal, ou seja, os sinais são automaticamente exportados. Para o sinal que temos mostrado (sinal Suponha que você execute o comando:
trap "" 2 e então execute um Subshell, que tornará a executar outro script como um Subshell. Se for gerado um sinal de interrupção, este não terá efeito nem sobre o Shell principal nem sobre os Subshell por ele chamados, já que todos eles ignorarão o sinal. Outra forma de restaurar um sinal ao seu default é fazendo: trap - sinal
Em korn shell ( echo -n "Senha: " stty -echo read Senha stty echo
O problema neste tipo de construção é que caso o operador não soubesse a senha, ele provavelmente daria um echo -n "Senha: " trap "stty echo exit" 2 3 stty -echo read Senha stty echo trap 2 3 Para terminar este assunto, abra uma console gráfica e escreva no prompt de comando o seguinte: $ trap "echo Mudou o tamanho da janela" 28
Em seguida, pegue o mouse (arghh!!) e arraste-o de forma a variar o tamanho da janela corrente. Surpreso? É o Shell orientado a eventos... Mais unzinho porque não pude resistir. Agora escreva assim: $ trap "echo já era" 17
Em seguida faça: $ sleep 3 &
Você acabou de criar um subshell que irá dormir durante três segundos em background. Ao fim deste tempo, você receberá a mensagem Para devolver estes sinais aos seus defaults, faça: $ trap 17 28
Ou $ trap - 17 28
Acabamos de ver mais dois sinais que não são tão importante como os que vimos anteriormente, mas vou registrá-los na tabela a seguir:
Muito legal este comando, né? Se você descobrir algum caso bacana de uso de sinais, por favor me informe por e-mail porque é muito rara a literatura sobre o assunto. Comando getopts
O comando Sintaxe: getopts cadeiadeopcoes nome
A -a argumento
Normalmente um ou mais espaços em branco separam o parâmetro da opção; no entanto, -aargumento
O
Como já sabemos, cada opção passada por uma linha de comandos tem um índice numérico, assim, a primeira opção estará contida em
Quando uma opção tem um argumento associado (indicado pelo O comando encerra sua execução quando:
O exemplo abaixo é meramente didático, servindo para mostrar, em um pequeno fragmento de código o uso pleno do comando. $ cat getoptst.sh
#!/bin/sh
# Execute assim: # # getoptst.sh -h -Pimpressora arq1 arq2 # # e note que as informacoes de todas as opcoes sao exibidas # # A cadeia 'P:h' diz que a opcao -P eh uma opcao complexa # e requer um argumento, e que h eh uma opcao simples que nao requer # argumentos. while getopts 'P:h' OPT_LETRA do echo "getopts fez a variavel OPT_LETRA igual a '$OPT_LETRA'" echo " OPTARG eh '$OPTARG'" done used_up=`expr $OPTIND - 1` echo "Dispensando os primeiros \$OPTIND-1 = $used_up argumentos" shift $used_up echo "O que sobrou da linha de comandos foi '$*'" Para entendê-lo melhor, vamos executá-lo como está sugerido em seu cabeçalho: $ getoptst.sh -h -Pimpressora arq1 arq2
getopts fez a variavel OPT_LETRA igual a 'h'
OPTARG eh ''
getopts fez a variavel OPT_LETRA igual a 'P'
OPTARG eh 'impressora'
Dispensando os primeiros $OPTIND-1 = 2 argumentos
O que sobrou da linha de comandos foi 'arq1 arq2'
Desta forma, sem ter muito trabalho, separei todas as opções com seus respectivos argumentos, deixando somente os parâmetros que foram passados pelo operador para posterior tratamento.
Repare que se tivéssemos escrito a linha de comando com o argumento ( $ getoptst.sh -h -P impressora arq1 arq2
getopts fez a variavel OPT_LETRA igual a 'h'
OPTARG eh ''
getopts fez a variavel OPT_LETRA igual a 'P'
OPTARG eh 'impressora'
Dispensando os primeiros $OPTIND-1 = 3 argumentos
O que sobrou da linha de comandos foi 'arq1 arq2'
Repare, no exemplo a seguir, que se passarmos uma opção inválida, a variável $ getoptst.sh -f -Pimpressora arq1 arq2 # A opção ?f não é valida
./getoptst.sh: illegal option -- f
getopts fez a variavel OPT_LETRA igual a '?'
OPTARG eh ''
getopts fez a variavel OPT_LETRA igual a 'P'
OPTARG eh 'impressora'
Dispensando os primeiros $OPTIND-1 = 2 argumentos
O que sobrou da linha de comandos foi 'arq1 arq2'
- Me diz uma coisa: você não poderia ter usado um - Poderia sim, mas para que? Os comandos estão aí para serem usados... O exemplo dado foi didático, mas imagine um programa que aceitasse muitas opções e seus parâmetros poderiam ou não estar colados às opções, suas opções também poderiam ou não estar coladas, ia ser um - É... Vendo desta forma acho que você tem razão. É porque eu já estou meio cansado com tanta informação nova na minha cabeça. Vamos tomar a saideira ou você ainda quer explicar alguma particularidade do Shell? - Nem um nem outro, eu também já cansei mas hoje não vou tomar a saideira porque estou indo dar aula na UniRIO, que é a primeira universidade federal que está preparando no uso de Software Livre, seus alunos do curso de graduação em informática. Mas antes vou te deixar um problema para te encucar: quando você varia o tamanho de uma tela, no seu centro não aparece dinamicamente em vídeo reverso a quantidade de linhas e colunas? Então! Eu quero que você reproduza isso usando a linguagem Shell. - Chico, traz rapidinho a minha conta! Vou contar até um e se você não trouxer eu me mando! Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em Shell que mande um e-mail para a nossa gerencia de treinamento para informar-se. Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para mim. Valeu! |
|||||||||||||||||||||||||||||||||
Licença Creative Commons - Atribuição e Não Comercial (CC) 2009 Pelos Frequentadores do Bar do Júlio Neves. Todo o conteúdo desta página pode ser utilizado segundo os termos da Creative Commons License: Atribuição-UsoNãoComercial-PermanênciaDaLicença. |