Bash Scripting

download Bash Scripting

of 73

Transcript of Bash Scripting

.----------------------------------. Programao em Bourne-Again Shell `------------------------------------, Por MELEU http://meleu.da.ru 05/2002 `------------------------------------------------------------------------' - = < N D I C E > = 0. Intro 1. Comeando 2. Variveis e Parmetros 2.1. Variveis do Usurio 2.1.1. Variveis Array 2.2. Variveis do Shell 2.3. Variveis Somente-Leitura 2.4. Parmetros 2.4.1. shift 2.4.2. set (para editar parmetros) 2.5. Substituio de Variveis 3. Entrada e Sada (I/O) 3.1. echo 3.1.1 Sequncias de Escape ANSI 3.2. read 3.3. Redirecionamento 3.3.1. Pipe 3.3.1.1. Comandos teis com o Pipe 4. Comandos de Tomadas de Deciso 4.1. if-then-else e afins 4.1.1. test 4.1.2. let 4.2. case 4.3. Tomadas de deciso com && e 4.3.1. Listas 5. Comandos de Loop 5.1. for 5.1.1 "for" como na linguagem C 5.2. while 5.3. until 5.4. break e continue 5.5. Redirecionando loops 6. Funes 6.1 Funes como comandos 7. Tornando seu Script Amigvel 7.1. getopts 7.2. select 7.3. dialog 8. Coisas teis de se aprender 9. Exemplos Variados 9.1. backup.sh 9.2. howto.sh

9.3. todo.sh 9.4. inseretxt.sh 9.5. Mextract.sh 10. Referncias 11. Consideraes Finais

-------------------------------------------------------------------------0. Intro ***** ***** PRIMEIRO DE TUDO ************************************************** * * * Esta a primeira verso do texto e ele est relativamente grande * * para que um nico mortal revise-o por inteiro, com o agravante de que * * este mortal um vestibulando. Por favor, se voc achar algum erro, * * algo mal explicado, ou tem alguma sugesto para que o texto fique * * melhor mande-me um email: [email protected] * * Quando eu tiver tempo eu acrescentarei mais coisas... * * * ************************************************************************* Well... aqui estamos de volta... Dessa vez o assunto shell script... Estou partindo do princpio de que ningum aqui tem dvidas quanto a utilidade de um shell script. Roubando uma citao de um amigo: "Em alguns casos, uma rede pode nao possuir um compilador (Vide Conectiva 5.0), logo, voce precisa se virar com o que tem, e os Shell Scripts podem suprir a sua necessidade em muitos casos." Eu j procurei um bocado de material sobre shell script em portugus na net e encontrei vrios. Porm a maioria sobre Korn Shell, C Shell, poucos eram sobre bash. E os de bash eram muito superficiais. Explicavam s o comeo de como criar seus shellscripts. Ento o que eu pretendo aqui entrar no assunto desde o incio e com alguns detalhes (talvez no muitos). Note tambm que muitas coisas explicadas aqui podem ser usadas em outros shells. Minhas fontes de pesquisa sero muito teis para voc, que um newbie dedicado. Portanto consulte a seo de referncias que voc vai achar muita coisa boa. O nico pr-requisito para o entendimento deste texto que o leitor tenha alguma familiaridade com os comandos UNIX. Uma noozinha de programao (algoritmos) cairia bem. Se voc no tem (ou acha que no tem) o pr-requisito acima citado, voc pode adquir-lo lendo o focalinux , ele um bom material em portugus sobre os comandos, uso, configurao, etc. do GNU/Linux. Leitura recomendada! Se voc sabe usar Expresses Regulares fica melhor ainda! Se no sabe aprenda a usar! Veja um guia sobre esse assunto na seo de referncias. de extrema importncia que voc v praticando assim que aprender algo novo, isso ajuda a se familiarizar e memorizar as coisas.

Por favor, no pense que sou um expert ou um guru em shell scripting! Eu s estava aprendendo e resolvi escrever isso pra ajudar quem tambm est afim de aprender. No se esquea: O aprendizado eterno! ;-) A maioria dos scripts chamam programas existentes no sistema, no ficarei explicando o que faz cada comando. Se voc quer saber o que ele faz, sua sintaxe e etc. procure na pgina man. Se voc tiver alguma dvida sobre o bash use: "help" ou "man bash". A manpage bastante completa (e grande tambm)! Use-a como referncia. Para sua comodidade eu coloquei os cdigos entre as tags do Phrack Extraction Utility. Voc pode encontr-lo na ltima edio da phrack em . Eu fiz um script em bash para extrao dos cdigos baseado no Phrack Extraction Utility, chama-se Meleu Extraction Utility (hehehe... qualquer semelhana NO mera coincidncia). Ele se encontra no tpico "9.5. Mextract.sh" e tambm em . O esquema de organizao o seguinte: exemplos bestas ficam no diretrio "BashScript/" os exemplos bacanas ficam no diretrio "BashScript/bacanas/". * Ateno na verso em que eu fiz os meus testes, pois em verses antigas algumas coisas podem no funcionar (este e o que vem na instalao do Slackware 8.0): /* -=-=-=-=-= version =-=-=-=-=- */ meleu@meleu:~$ bash --version GNU bash, version 2.05.0(1)-release (i386-slackware-linux-gnu) Copyright 2000 Free Software Foundation, Inc. /* -=-=-=-=-= version =-=-=-=-=- */ Agradecimentos: A todos que fazem um esforcinho para publicar informaes de qualidade em portugus. Especialmente para meus amiguinhos(as): lucipher, klogd, module, eSc2, xf, Emmanuele, Mana_Laura, NashLeon, Hekodangews, Blind_Bard, clausen, Renato , hts, EvilLord, aurlio (assim como eu tambm um dinossauro-amante-do-modo-texto), s pessoas que levam a Unsekurity Scene a srio, aos camaradas da EoH Team , e outros pessoas que eu posso no me lembrar agora mas que tambm so meus camaradas. lgico que tambm devo agradecimentos a toda a comunidade Open Source, sem a qual tudo isso aqui no existiria! Amo vocs! =D LICENSA: No quero nenhuma exclusividade! Quero informao fluindo! Pegue este texto e espalhe em todo lugar em que ele for bem-vindo. Se quiser extrair trechos dele e puder fazer o favor de citar de onde foi extrado, eu me sentiria agradecido.

--------------------------------------------------------------------------

1. Comeando *********

Como voc j deve saber, um shell script um arquivo em formato texto puro que contm comandos/instrues para serem executados em uma determinada shell. O que vou tentar passar neste texto como fazer shell script para o Bourne-Again Shell, ou bash. Esta uma linguagem interpretada (voc no precisa compilar para ter o executvel) e o bash o interpretador. Veja um exemplo de script: /* --------------- */ BashScript/primeiroexemplo.sh #!/bin/bash echo 'Alo mame!' echo echo 'Agora executarei um simples "ls -l", veja: ' echo ls -l /* --------------- */ Para que se possa executar um shell script necessrio permisso de execuo (mais sobre permisses em http://meleu.da.ru/index.html#textos ). Para que somente voc (dono do arquivo) tenha permisso de execuo para o primeiroexemplo.sh voc faz: $ chmod u+x primeiroexemplo.sh Agora voc pode executar o script da seguinte forma: $ ./primeiroexemplo.sh Veja outro exemplo de apenas um comando: /* ----------------- */ BashScript/procura_suid.sh #!/bin/bash # script para procurar arquivos suid # que pertenam a determinado usurio find / -user $1 -perm -4000 2> /dev/null /* ----------------- */ Agora vamos a uma rpida explicao sobre o cdigo... - Na primeira linha ns dizemos qual ser o nosso intrepretador de comandos (o shell). Voc deve comear a linha com um "#!" (conhecido como sha-bang) e depois o caminho inteiro para o bash. - Nas segunda e terceira linhas so usados comentrios, todo comentrio comea com uma cerquilha (#) e vai at o final da linha; - A ltima linha que realmente o comando, o $1 significa o primeiro parmetro dado na linha de comando (ser falado mais sobre isso daqui a pouco), por exemplo: $ ./procura_suid.sh level5 ir procurar por todos os arquivos suid que pertenam ao usurio level5. Como voc deve ter reparado, esse shell script til nos wargames (veja 10. Referncias), mas tem que ser muito preguioso pra fazer um shell script de um comando s! :P De vez em quando bom observar o que o script est fazendo. Para isso voc pode usar alguns parmetros junto com o shell para executar seu

script. Veja: /* -=-=-=-=-=-= debugar =-=-=-=-=-=- */ $ bash -x BashScript/primeiroexemplo.sh + echo 'Alo mame!' Alo mame! + echo + echo 'Agora executarei um simples "ls -l", veja: ' Agora executarei um simples "ls -l", veja: + echo + ls -l total 12 drwxr-xr-x 5 drwxr-xr-x 2 drwxr-xr-x 2 /* -=-=-=-=-=-=

meleu meleu meleu debugar

users users users =-=-=-=-=-=-

4096 Aug 18 15:28 GNUstep 4096 Aug 19 23:11 progs 4096 Aug 19 22:57 txts */

O parmetro "-x" faz com que seja exibido o comando e depois a sada do comando. Outros parmetros interessantes para a "debuagao" do script so: -n -v no executa os comandos, apenas verifica erros de sintaxe (noexec); mostra o script e depois executa-o (verbose);

Outra coisa que devemos saber que quando um shell script executado ele usa OUTRA SHELL e NO USA A SHELL ATUAL. Desculpem eu estar berrando deste jeito... :P mas importante termos isso em mente quando formos usar variveis. Falando em variveis...

--------------------------------------------------------------------------

2. Variveis e Parmetros ********************** Ao contrrio das outras linguagens, o bash no possui "tipos de dados", todas as variveis so strings. O bash usa strings para representar todos os dados que sero usados pelas variveis. A seguir falaremos sobre os *tipos de variveis* (e no "tipos de dados"). Se voc conhece alguma outra linguagem de programao sabe que os identificadores possuem algumas regras quanto a sua nomeclatura. Pois no bash as regras so parecidssimas: * * * E * S se pode usar caracteres alfanumricos e underline; S se pode comear com letra ou underline (nmero no pode); No pode conter espaos em branco; uma coisa que ns, falantes da lngua portuguesa temos que saber : Os identificadores NO podem conter acentos!

enfim... todas aquelas regrinhas para identificadores de linguagens de programao tambm se aplica aqui, exceto aquela famosa sobre palavras

reservadas. Voc pode por exemplo fazer "if=lalala" que funcionar perfeitamente. A nica coisa que no pode usar um nome que j tenha sido definido para uma outra varivel e que esta seja "readonly" (mais sobre isso adiante). Tambm deve-se tomar cuidado para no fazer bobagens com as variveis do shell (explicados no tpico 2.2.).

2.1. Variveis do Usurio ==================== As variveis do usurio so as variveis que voc pode declarar, ler, inicializar e modificar. No exemplo abaixo ns criamos uma varivel chamada "nome" e atribumos a ela o valor "Meleu". Veja: $ nome=Meleu No pode haver espaos nem antes nem depois do sinal de '='! Se voc quiser atribuir um valor que contenha espaos necessrio usar as 'aspas simples'. Veja: $ nome='Meleu nao eh meleca!' Agora para usar a varivel s voc colocar um cifro '$' antes do nome dela. Olhe um exemplo com e sem o '$': $ echo nome nome $ echo $nome Meleu no eh meleca! Existe diferena entre usar 'aspas simples', "aspas duplas", `crases` e no usar nada. Veja isto: /* -=-=-=-=-= exemplos =-=-=-=-=- */ $ caminho='O meu path eh: $PATH' $ echo $caminho O meu path eh: $PATH $ caminho="O meu path eh: $PATH" $ echo $caminho O meu path eh: /usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/usr/openwin/bin $ teste=`ls $HOME` $ echo $teste GNUstep/ progs/ textos/ $ conteudo_dir="Meu diretorio home contem: `ls $HOME`" $ echo $conteudo_dir Meu diretorio home contem: GNUstep/ progs/ textos/ $ teste=isso nao eh valido bash: nao: command not found $ teste=mas_isso_eh_valido $ echo $teste mas_isso_eh_valido

/* -=-=-=-=-= exemplos =-=-=-=-=- */ Os mais espertos j perceberam as diferenas... mas para os mais lerdinhos (como eu) a vai uma explicao. + 'aspas simples': atribuem varivel EXATAMENTE o que est entre elas; + `crases`: atribuem varivel a *sada do comando* que est entre elas, tem a capacidade de ver o contedo de uma varivel (no exemplo acima, a varivel de ambiente $HOME); + "aspas duplas": atribuem varivel a string, o valor das variveis que porventura podem estar entre elas (no segundo exemplo, a varivel de ambiente $PATH), e tambm a sada de comandos que estejam entre `crases`; + nada: similar as aspas duplas, porm ignora espaos excedentes. Podemos usar $(cifro-parnteses) no lugar das crases. Em alguns casos melhor usar $(cifro-parnteses) mas eu no vou falar em quais, voc vai descobrir quando. ;-) Veja estes exemplo: /* -=-=-= exemplo =-=-=- */ $ dir_atual=$(pwd) $ echo $dir_atual /home/meleu $ echo $(ls $HOME) GNUstep/ progs/ textos/ $ tar czvf backup_$(date +%d-%m-%Y).tgz arquivo /* -=-=-= exemplo =-=-=- */ Outra coisa interessante o uso das {chaves}. Voc pode usar as chaves para exibir uma varivel (ex.: echo ${teste}), isso til quando voc precisa separar a varivel do que vem depois dela. Veja isto: /* -=-=-=-=-= exemplo =-=-=-=-=- */ $ name=coracao $ echo ${name}deleao coracaodeleao /* -=-=-=-=-= exemplo =-=-=-=-=- */ Como eu disse anteriormente, quando executamos um shell script ele usa outro shell, portanto toda varivel que for criada/inicializada num shell script perder seu valor no final da execuo do mesmo. No entanto, voc pode fazer um shell script usar variveis de usurio exportando-a com o comando "export" (ver man page do bash). Um exemplo simples: /* -=-=-=-=-= exemplo =-=-=-=-=- */ $ cat teste.sh #!/bin/bash echo "$VAR" $ export VAR='Um abraco para os gajos de Portugal! :)' $ ./teste.sh Um abraco para os gajos de Portugal! :)

$ export VAR='--> mudei a variavel e > l > e > u' m e l e u /* -=-=-= exemplo =-=-=- */ Este sinal '> ' (maior-espao) o PS2. Voc pode usar os mesmos caracteres especiais que o PS1 usa. --> MAIL Nada mais do que o arquivo onde so guardados seus emails. Aqui na minha mquina eu uso o sendmail como servidor de email, portanto: /* -=-=-= MAIL =-=-=- */ meleu@meleu:~$ echo $MAIL /var/spool/mail/meleu /* -=-=-= MAIL =-=-=- */ porm se estivesse usando qmail seria: /* -=-=-= MAIL =-=-=- */ meleu@meleu:~$ echo $MAIL /home/meleu/Mailbox /* -=-=-= MAIL =-=-=- */ --> SHLVL Esta varivel armazena quantos shells voc executou a partir da primeira shell. Confuso? Vamos a um exemplo. Imagine que voc est usando o bash e executou o bash de novo, nesta situao o seu SHLVL vale 2. Veja isto: /* -=-=-= exemplo =-=-=- */ $ echo $SHLVL 1 $ bash # estou executando o bash a partir do bash $ echo $SHLVL 2 $ exit # sa do segundo bash exit

$ echo $SHLVL 1 /* -=-=-= exemplo =-=-=- */ Quando voc inicializa scripts a partir do comando "source" o script executado no shell pai, portanto se tiver um "exit" no script voc vai executar um logoff. a que est a utilidade da varivel SHLVL. Quando voc est no shell primrio o valor de SHLVL 1. Ento voc pode, atravs de um "if" por exemplo, executar o "exit" s se SHLVL for diferente de 1 (mais informaes sobre o source em "6.1 Funes como comandos").

--> PROMPT_COMMAND Esta bem interessante. Ela armazena um comando que ser executado toda hora que o prompt exibido. Veja: /* -=-=-= exemplo =-=-=- */ $ PROMPT_COMMAND="date +%T" 19:24:13 $ cd 19:24:17 $ ls GNUstep/ bons.txt pratica/ teste worldwritable.txt Mail/ hacking/ progs/ txts/ 19:24:19 $ 19:24:32 $ # isso eh uma linha sem nenhum comando 19:24:49 $ /* -=-=-= exemplo =-=-=- */ Esta varivel til quando queremos brincar com o prompt, para aprender mais sobre isso leia o Bash-Prompt-HOWTO (v. 10. Referncias). --> IFS O shell usa esta varivel para dividir uma string em palavras separadas. Normalmente o IFS um espao, uma tabulao (Tab) e um caractere nova linha (\n). Desta maneira: isto eh uma string so quatro palavras, pois IFS um espao e as palavras esto separadas por espao. Agora se eu mudar IFS para um ':' desta maneira: IFS=':' ento a string: isto:eh:uma:string conter quatro palavras. Isto til para casos como neste exemplo: /* ----------------- */ BashScript/path.sh #!/bin/bash

IFS=':' for item in $PATH ; do echo $item done /* ----------------- */ Se IFS for uma varivel nula (vazia), tudo ser considerado uma nica palavra. Por exemplo: se o IFS for nulo, toda essa linha ser considerada uma nica palavra

--> RANDOM Quando voc exibe esta varivel ("echo $RANDOM") exibido um nmero aleatrio entre 0 e 32767. Pra que serve isso? Sei l! Vrias coisas. Quem criativo sempre precisa de um nmero aleatrio... Imagine que voc queira um nmero de telefone celular qualquer (sei l pra qu!), voc pode fazer um script que gera um nmero desse pra voc. Aqui na minha regio estes nmeros comeam com 99 ou 98, e tm um total de 8 dgitos. O script a seguir gera nmeros que comecem com 98 somente: /* ----------------- */ BashScript/cellnumbergen.sh #!/bin/bash NUM="98$(echo $RANDOM)0" CONT=$(echo -n $NUM wc -c) while [ $CONT -lt 8 ]; do NUM=${NUM}0 CONT=$(echo -n $NUM done echo $NUM /* ----------------- */ --> Outras Outras variveis que so muito usadas: MAILCHECK ; HISTFILE ; HOSTNAME ; LS_OPTIONS ; LS_COLOR ; MANPATH ; SHELL ; TERM ; USER ; PS3 . Estas so as mais utilizadas, porm existem muitas outras. Para ver quais so as variveis definidas no momento basta entrar com o comando "set". E para ver apenas as variveis de ambiente use "env". Olhe a man page do bash na seo "Shell Variables" para mais detalhes. # quantos digitos tem? # se nao tiver 8 digitos acrescenta 0's wc -c)

2.3. Variveis Somente-Leitura

========================= Como sabemos as variveis podem ter seu valor modificado pelo usurio, mas se ns quisermos variveis que NO possam ter seus valores alterados basta declararmos tal varivel como somente-leitura. Para tornar uma varivel read-only podemos usar o comando "readonly" ou ento "declare -r". Veja os exemplos a seguir, ambos possuem o mesmo resultado: /* -=-=-=-=-= exemplo-1 =-=-=-=-=- */ $ readonly NOME="Meleu Zord" $ echo $NOME Meleu Zord /* -=-=-=-=-= exemplo-1 =-=-=-=-=- */ /* -=-=-=-=-= exemplo-2 =-=-=-=-=- */ $ declare -r NOME="Meleu Zord" $ echo $NOME Meleu Zord /* -=-=-=-=-= exemplo-2 =-=-=-=-=- */ Agora s pra ter certeza: /* -=-=-= teste =-=-=- */ $ NOME=Fulano bash: NOME: readonly variable $ echo $NOME Meleu Zord /* -=-=-= teste =-=-=- */ Um bom uso deste tipo de varivel para garantir que variveis importantes de um determinado script no possam ser sobregravadas, evitando assim algum resultado crtico. O comando "readonly" quando usado sem parmetros (ou o comando "declare" apenas com o parmetro "-r") nos mostra todas as variveis declaradas como somente-leitura. No exemplo a seguir se for usado "declare -r" no lugar de "readonly" teramos a mesma sada. /* -=-=-=-=-= readonly =-=-=-=-=- */ $ readonly declare -ar BASH_VERSINFO='([0]="2" [1]="05" [2]="0" [3]="1" [4]="release" [5]="i386-slackware-linux-gnu")' declare -ir EUID="1005" declare -ir PPID="1" declare -r SHELLOPTS="braceexpand:hashall:histexpand:monitor:ignoreeof:interactive-comments :emacs" declare -ir UID="1005" /* -=-=-=-=-= readonly =-=-=-=-=- */ Existem vrias variveis somente-leitura que so inicializadas pelo shell, como USER, UID. TODAS as variveis readonly uma vez declaradas no podem ser "unsetadas" ou ter seus valores modificado. O nico meio de apagar as variveis readonly declaradas pelo usurio saindo do shell (logout).

2.4. Parmetros ========== Podemos passar parmetros para o shell script assim como na maioria dos programas. Os parmetros so variveis, digamos, especiais. Para comear elas no obedecem as regras de nomeclatura de variveis, pois elas usam nmeros; e tambm ns no podemos mudar o valor destas variveis pelas vias "tradicionais", para mudar o valor destas ns temos que contar com a ajuda do shift e/ou do set (como veremos adiante). Veja esta relao: $0 $1 a $9 ${10}, ${11}... $* $@ $# Outros: $? $$ valor de retorno do ltimo comando (explicado mais adiante); PID do script. o nome do shell script (a.k.a. parmetro zero); $1 o primeiro parmetro, $9 o nono, e assim por diante; quando o nmero do parmetro possui mais de um dgito necessrio o uso das chaves; todos os parmetros em uma nica string (exceto o $0); todos os parmetros, cada um em strings separadas (exceto $0); nmero de parmetros (sem contar com o $0).

Pra ficar mais claro, nada melhor do que um exemplo: /* ------------------ */ BashScript/parametros.sh #!/bin/bash # # "basename" serve para eliminar o caminho do arquivo e mostrar # somente o ltimo nome dele. Neste caso: parametros.sh echo "Nome do script: `basename $0`" echo "Nmero total de parmetros: $#" echo "Primeiro parmetro: $1" echo "Segundo parmetro: $2" echo "Dcimo quinto parmetro: ${15}" echo "Todos os parmetros: $*" /* ------------------ */ /* -=-=-=-=-= exemplo =-=-=-=-=- */ $ ./parametros.sh a b c d e f g h i j l m n o p q r s t u v x z Nome do script: parametros.sh Nmero total de parmetros: 23 Primeiro parmetro: a Segundo parmetro: b Dcimo quinto parmetro: p Todos os parmetros: a b c d e f g h i j l m n o p q r s t u v x z

/* -=-=-=-=-= exemplo =-=-=-=-=- */ Se voc no entendeu direito a diferena entre o $* e o $@, ento d uma olhada no seguinte script (se no entend-lo tudo bem, siga em frente e quando aprender sobre o "if" e o "for" leia-o novamente): /* ------------------ */ BashScript/testargs.sh #!/bin/bash # Ao executar este script entre alguns parametros. Ex.: # [prompt]$ ./testargs.sh um dois tres quatro if [ -z "$1" ]; then echo "Uso: `basename $0` argumento1 argumento2 etc." exit 1 fi echo echo "Listando argumentos com \"\$*\":" num=1 for arg in "$*"; do echo "Arg #$num = $arg" num=$[ $num + 1 ] done # Concluso: $* mostra todos os argumentos como uma nica string echo echo "Listando argumentos com \"\$@\":" num=1 for arg in "$@"; do echo "Arg #$num = $arg" num=$[ $num + 1 ] done # Concluso: $@ mostra cada argumento em strings separadas echo /* ------------------ */

2.4.1. shift ----O bash possui um comando embutido que lida com parmetros, o shift. Quando voc usa o shift sai o primeiro parmetro da lista e o segundo vai para $1 o terceiro vai para $2, e assim por diante. Voc pode ainda especificar quantas "casas" voc quer que os parmetros "andem" esquerda atravs de "shift n" onde 'n' o nmero de casas, mas se o nmero de casas que ele deve andar for maior que o nmero de parmetros o shift no executado. Veja este exemplo: /* ------------------ */ BashScript/shift-exemplo.sh #!/bin/bash echo "$#: $*" echo -e "executando \"shift\"" shift

echo "$#: $*" echo -e "executando \"shift 5\"" shift 5 echo "$#: $*" echo -e "executando \"shift 7\"" shift 7 echo "$#: $*" /* ----------------- */ /* -=-=-=-=-= shift =-=-=-=-=- */ $ ./shift-exemplo.sh 1 2 3 4 5 6 7 8 9 0 10: 1 2 3 4 5 6 7 8 9 0 executando "shift" 9: 2 3 4 5 6 7 8 9 0 executando "shift 5" 4: 7 8 9 0 executando "shift 7" 4: 7 8 9 0 /* -=-=-=-=-= shift =-=-=-=-=- */ Os valores que saem so perdidos. Use com ateno!

2.4.2. set (para editar parmetros) ---------------------------O que vou passar neste tpico no sobre como usar "todo o poder do comando set", e sim como usar set especificamente para editar parmetros. No tem nenhum segredo! Veja este exemplo: set um dois tres Isso far com que $1 seja 'um', $2 seja 'dois', $3 seja 'tres' e s! No existir $4, $5, etc. mesmo que eles tenham sido usados. Veja um exemplo de script: /* ----------------- */ BashScript/setparam.sh #!/bin/bash echo "Os $# parmetros passados inicialmente foram: $@" echo echo "e agora eu vou alter-los!" echo "como eu sou mau... (huahuahau risada diablica huahuahuha)" echo set um dois tres echo "Os $# novos parmetros agora so: $@" echo /* ----------------- */ No interessa quantos parmetros voc passar para este script, no final voc s ter $1, $2 e $3 valendo 'um', 'dois' e 'tres', respectivamente. No meu Mextract.sh (tpico 9.5.) esta caracterstica do set muito bem aproveitada! ;-)

2.5. Substituio de Variveis ========================= Isto muito til e pode ser muito mais elegante que ficar usando if's (explicados mais adiante) sem necessidade! Veja que bacana! ;-) --> ${variavel:-string} Se "variavel" no tiver sido definida ou for vazia ser substituda por "string". O valor da varivel no alterado. Veja este exemplo: /* -=-=-= exemplo =-=-=- */ $ echo ${URL:-"http://unsekurity.virtualave.net"} http://unsekurity.virtualave.net $ echo $URL # observe que URL nao foi alterado /* -=-=-= exemplo =-=-=- */ --> ${variavel:=string} Se "variavel" no estiver sido definida ou for vazia, receber "string". Exemplo: /* -=-=-= exemplo =-=-=- */ $ echo ${WWW:="http://meleu.da.ru"} http://meleu.da.ru $ echo $WWW http://meleu.da.ru /* -=-=-= exemplo =-=-=- */ --> ${variavel:?string} Se "variavel" no estiver sido definido ou for vazia, "string" ser escrito em stderr (sada de erro padro). O valor da varivel no alterado. Veja um exemplo: /* -=-=-= exemplo =-=-=- */ $ echo ${EDITOR:?"Nenhum editor de texto"} bash: EDITOR: Nenhum editor de texto $ echo $EDITOR /* -=-=-= exemplo =-=-=- */ --> ${variavel:+string} Se "variavel" estiver definida, ser substituda por "string" mas seu valor no ser alterado. Exemplo: /* -=-=-= exemplo =-=-=- */ $ echo ${BROWSER:+"BROWSER definido como \"$BROWSER\""} BROWSER definido como "links" /* -=-=-= exemplo =-=-=- */

--------------------------------------------------------------------------

3. Entrada e Sada (I/O) ********************* Comunicando-se...

3.1. echo ==== Nos j usamos o echo para escrever na tela, mas aqui vamos tratar de alguns "segredinhos" (que no so to secretos assim). Existem alguns momentos que voc no quer que a sada do echo pule de linha automaticamente. Para isso use o parmetro "-n". Este parmetro til quando voc vai entrar com algo aps o echo. Veja este script: /* ----------------- */ BashScript/filetype.sh #!/bin/bash echo -n "Entre com o nome do arquivo: " read FILE echo "Tipo do arquivo `file $FILE`" /* ----------------- */ Execute e veja o resultado. Muita ateno deve ser tomada ao usar o echo, pois as aspas que voc pode vir a deixar de usar podem fazer uma diferena danada (em alguns casos isso pode ser muito til). /* -=-=-= exemplo =-=-=- */ $ echo uma boa rede de irc que conheco eh irc.linux.org uma boa rede de irc que conheco eh irc.linux.org $ echo "uma boa rede de irc que conheco eh irc.linux.org" uma boa rede de irc que conheco eh irc.linux.org $ $ # agora um exemplo com variavel $ $ TESTE="primeira linha da variavel > segunda linha > terceira... > chega! :) > " $ echo $TESTE primeira linha da variavel segunda linha terceira... chega! :) $ echo "$TESTE" primeira linha da variavel segunda linha terceira... chega! :) /* -=-=-= exemplo =-=-=- */

A esta altura voc j deve ter se perguntado "Como fao para imprimir caracteres nova linha ou beep?!". Os mais malandrinhos devem ter tentado um contra-barra (backslash) '\', mas voc no pode simplesmente fazer isso. necessrio usar o parmetro "-e" com o echo. Este parmetro permite que usemos sequncias de escape contra-barra. As sequncias so iguais a da linguagem C, exemplo: \n para nova linha, \a para beep, \b para backspace, etc... Veja este exemplo: /* -=-=-= exemplo =-=-=- */ $ echo -e "module caiu de cara tentando \"top soul\".\nQue paia\a"! module caiu de cara tentando "top soul". Que paia! /* -=-=-= exemplo =-=-=- */ O -e tambm usado para escrever coloridinho (ai que fofo!), e outras coisas interessantes. Veremos isso no tpico seguinte.

3.1.1 Sequncias de Escape ANSI ------------------------Para usar cores a sequncia de escape "\e[m" (os sinais '' no entram!). Veja um exemplo (mais a frente voc ver tabelas com os significados destas sequncias): /* ----------------- */ BashScript/amarelinho.sh #!/bin/bash # imprime amarelinho no centro da linha # # # [ A varivel $COLUMNS contm o nmero de colunas que o terminal est usando, e antes de executar este script voc precisa export-la: [prompt]$ export COLUMNS $COLUMNS ] { echo Voc precisa exportar a varivel \"COLUMNS\": echo "Tente \"export COLUMNS\" e tente executar novamente" exit 1

} POSICAO=$[ ( $COLUMNS - `expr length "$*"` ) / 2 ] # `expr length "$*"` retorna o nmero de caracteres digitados # como parmetros. echo -e "\e[${POSICAO}C\e[33;1m$*\e[0m" /* ----------------- */ Agora uma explicao ligeira: o \e diz ao echo que o que vem depois uma sequncia de escape. Se voc der a sequncia '[C', onde num um nmero qualquer, o cursor vai andar "num" caraceteres para a direita. Acima eu uso a varivel POSICAO para mover o cursor para o centro da linha (veja o clculo no cdigo). O comando '[m' muda para a cor "num". Cada cor tem um cdigo prprio. No exemplo acima o 33 faz ficar marrom, porm combinando com o 1

fica amarelo (isso no modo texto, pois no xterm, por exemplo, o 1 faz o marrom ficar em negrito. veja OBSERVAES mais adiante). Veja uma tabela com os cdigos de movimentao de cursor que eu conheo (os caracteres '' devem ser ignorados): ,-------------,------------------------------------------------, Cdigo O que faz ------------- -----------------------------------------------\e[A Move o cursor N linhas acima. ------------- -----------------------------------------------\e[B Move o cursor N linhas abaixo. ------------- -----------------------------------------------\e[C Move o cursor N colunas direita. ------------- -----------------------------------------------\e[D Move o cursor N colunas esquerda. ------------- -----------------------------------------------\e[E Move o cursor N linhas para baixo na coluna 1. ------------- -----------------------------------------------\e[F Move o cursor N linhas para cima na coluna 1. ------------- -----------------------------------------------\e[G Coloca o cursor na linha N. ------------- -----------------------------------------------\e[;H Coloca o cursor na linha L e na coluna C. ------------- -----------------------------------------------\e[I Move o cursor N tabulaes direita. ------------- -----------------------------------------------N=0 Apaga do cursor at o fim da tela; \e[J N=1 Apaga do cursor at o incio da tela; N=2 Apaga a tela toda. ------------- -----------------------------------------------N=0 Apaga do cursor at fim da linha; \e[K N=1 Apaga do cursor at o incio da linha; N=2 Apaga a linha toda. ------------- -----------------------------------------------\e[L Adiciona N linhas em branco abaixo da atual. ------------- -----------------------------------------------\e[M Apaga N linhas abaixo da atual. ------------- -----------------------------------------------\e[P Apaga N caracteres a direita. ------------- -----------------------------------------------\e[S Move a tela N linhas para cima. ------------- -----------------------------------------------\e[T Move a tela N linhas para baixo. ------------- -----------------------------------------------\e[X Limpa N caracteres direita (com espaos). ------------- -----------------------------------------------\e[@ Adiciona N espaos em branco. ------------- -----------------------------------------------\e[s Salva a posio do cursor. ------------- -----------------------------------------------\e[u Restaura a posio do cursor que foi salva. '-------------'------------------------------------------------' Sim, a lista grande... Faa uns testes para praticar um pouquinho. Agora uma tabelinha dos atributos e seus nmeros (N deve estar no formato "\e[m"): ,-----------------------------,----,-------------,---,

Atributo N Cor X ----------------------------- ---- ------------- --Desligar todos atributos 0 Preto 0 Negrito 1 Vermelho 1 Cor X para o primeiro plano 3X Verde 2 Cor X para o segundo plano 4X Marrom 3 Sublinhado 4 Azul 4 Piscando (blink) 5 Roxo 5 Vdeo reverso 7 Ciano 6 -x-- Branco 7 '-----------------------------'----'-------------'---' OBSERVAES: -> Negrito, Sublinhado e Piscando possuem comportamentos diferentes no console e nos emuladores de terminal. Principalmente quando temos negrito sendo usado com cores. Por exemplo, o cdigo "\e[33m" ir ativar o marrom mas se for usado (no console!) com o atributo de negrito ficar amarelo, e o cdigo ser assim: "\e[1;33m". Por isso faa os testes que voc descobrir as cores -> Estas tabelas eu fiz graas a uma matria que o aurlio escreveu sobre isso. Veja em http://verde666.org/coluna/ No tpico "6.1 Funes como comandos" voc ver o Mfunctions, ele contm uma funo que mostra todas as combinaes de cores possveis.

3.2. read ==== Como voc viu no script anterior para entrar com um dado usa-se "read". O read tem alguns "macetinhos". Pra comear: voc no precisa colocar um echo toda hora que for usar o read para escrever um prompt. Basta fazer "read -p prompt variavel" Veja esta seo de exemplos: /* ----------------- */ BashScript/read1.sh #!/bin/bash read -p "Entre com uma string: " string echo $string /* ----------------- */ /* -=-=-=-=-= exemplo =-=-=-=-=- */ $ ./read1.sh Entre com uma string: klogd eh um tremendo cachacero! klogd eh um tremendo cachacero! /* -=-=-=-=-= exemplo =-=-=-=-=- */ /* ----------------- */ BashScript/read2.sh #!/bin/bash read -p "Entre com 3 strings: " s1 s2 s3 echo "s1 = $s1 s2 = $s2 s3 = $s3" /* ----------------- */ /* -=-=-=-=-= exemplo2 =-=-=-=-=- */

$ ./read-2.sh Entre com 3 strings: j00nix eh cabecudo s1 = j00nix s2 = eh s3 = cabecudo # o mesmo script com mais de 3 strings # $ ./read-2.sh Entre com 3 strings: eSc2 adora ficar de copy'n'paste no IRC. s1 = eSc2 s2 = adora s3 = ficar de copy'n'paste no IRC. /* -=-=-=-=-= exemplo2 =-=-=-=-=- */ Quando o atribuda a cada string o nmero de "read" vai ler apenas uma varivel, toda a string vai ser esta varivel. Quando vai ler mais de uma varivel ele atribui a sua respectiva varivel; e quando o nmero de strings excede variveis a ltima fica com o excedente.

O parmetro "-s" serve para no ecoar o que for digitado. til para digitar uma senha por exemplo. Tente "read -s PASS" e veja. Voc tambm pode determinar o nmero de caracteres que sero lidos com o parmetro "-n". Tente fazer "read -n 10 VAR". Mas cuidado: ao usar a opo -n voc no poder usar o backspace para fazer correes. A opo "-r" serve para que a contra-barra (backslash) no aja como um caracter de escape. E isso me foi bastante til para fazer o Mextract, como voc ver adiante. Mais sobre o read na manpage do bash.

3.3. Redirecionamento ================ Quem j sabe programar deve saber que existem trs "file descriptors" abertos por padro (pelo menos nos sistemas operacionais que conheo): stdin (standard input), stdout (standard output) e stderr (standard error). Para fins prticos, estes so considerados arquivos e voc pode direcionar destes "arquivos" para outros e vice-versa. Veja como direcionar de: + arquivo para stdin $ programa < arquivo + stdout para arquivo $ programa > arquivo + stderr para arquivo $ programa 2> arquivo + stdout para stderr $ programa 1>&2 + stderr para stdout $ programa 2>&1 + stdout e stderr para arquivo $ programa &> arquivo Se voc usar por exemplo "find / -perm -2 > worldwritable.txt" e no

diretrio no tiver um arquivo chamado "worldwritable.txt" este ser criado, a sada do comando ser gravada nele e a sada de erro padro ser impressa na tela (ou cran, se preferirem :P ). Para no ver as mensagens de "Permission Denied" faa isso: $ find / -perm -2 > worldwritable.txt 2> /dev/null Ainda temos um probleminha: este comando ir mostrar tambm todos os links simblicos e vrios arquivos de dispositivo. Para eliminar os links simblicos faa o seguinte: $ find / -perm -2 ! -type l > worldwritable.txt 2> /dev/null Voc ainda pode eliminar da sada os arquivos com stick bit e os arquivos de dispositivo usando parnt... EI!! Isto aqui sobre redirecionamento, e no sobre o find! V ler a man page do find! =P Se o arquivo j existir seu contedo ser sobregravado. Mas voc pode apenas concatenar o contedo no final do arquivo usando ">>". Exemplo: $ echo " F I M D O A R Q U I V O " >> worldwritable.txt Faa os testes e tire suas concluses! ;) Veja este script a seguir a execute ele usando redirecionamento na linha de comando pra ver os resultados /* ----------------- */ BashScript/redirecionamento.sh #!/bin/bash echo "Isto vai para a sada padro." echo "Isto vai para a sada de erro padro." 1>&2 echo "Isto vai criar um arquivo e colocar esta linha nele." > ARQUIVO echo "Esta linha vai para o final do arquivo." >> ARQUIVO /* ----------------- */ Tem um outro tipo de redirecionamento que bastante til. assim: $ programa xargs O xargs transforma stdin em argumentos da linha de comando. Vamos usar o exemplo anterior de novo: /* -=-=-=-=-= exemplo =-=-=-=-=- */ $ who cut -c-9 # lembrando: pipe transforma stdout em stdin meleu hack root

$ # "echo" nao le arquivo, ele usa argumentos. $ # A linha abaixo nao tem utilidade. $ who cut -c0-9 echo $ # "xargs" transforma o conteudo de stdin em argumentos $ who cut -c0-9 xargs echo meleu hack root /* -=-=-=-=-= exemplo =-=-=-=-=- */ Como eu gosto do find no resisti e colocarei um comando interessante que usa pipe e xargs: $ find / -perm -2 ! -type l ! -type c xargs ls -ld > wordwritable.txt

Se no entendeu algo do comando acima e quer entender, olhe as manpages. --> tee Outro comando bom de se usar com pipe o "tee". Ele faz com que a sada do programa v para a sada padro, normalmente a tela (cran) *E* para um arquivo ao mesmo tempo. como se voc fizesse "programa > arquivo" s que o sada do programa tambm seria escrita na sada padro. Experimente: $ ls -la tee conteudo.txt

--------------------------------------------------------------------------

4. Comandos de Tomadas de Deciso ****************************** Agora sim o negcio comea a ficar legal! :-) O jeito como as estruturas esto explicadas o que eu uso, mas no o nico. Se voc quer uma referncia mais completa veja a manpage do bash. 4.1 if-then-else e afins ==================== A estrutura bsica a seguinte: if ; then else fi Primeiro devemos saber que todos os comandos do UNIX possuem um cdigo de retorno. Este cdigo tem valor 0 quando a operao ocorre com sucesso e valor diferente de zero quando a operao NO termina com sucesso. Aps

cada comando o valor de retorno gravado na varivel $?, experimente um "echo $?" depois de algum comando e veja! A avaliao de verdadeiro do bash exatamente o oposto de outras linguagens de programao (C por exemplo), que avaliam a expresso de retorno diferente de 0 como verdadeira e 0 como falso. No bash, quando um comando retorna 0 o if avalia como verdadeiro e quando retorna um no-zero significa falso. (Para mais detalhes sobre os cdigos de retorno, olhe a pgina manual do bash na seo "EXIT STATUS"). Veja um exemplo: /* ----------------- */ BashScript/return.sh #!/bin/bash read -p "Entre com o nome do diretrio: " DIR if ( cd $DIR 2> /dev/null ); then echo -e "'cd $DIR' retornou \"sucesso\" ($?)" else echo -e "'cd $DIR' retornou \"insucesso\" ($?)" fi /* ----------------- */ /* -=-=-=-=-= exemplo =-=-=-=-=- */ meleu:~$ ./return.sh Entre com o nome do diretrio: /usr 'cd /usr' retornou "sucesso" (0) meleu:~$ ./return.sh Entre com o nome do diretrio: dir_invalido 'cd dir_invalido' retornou "insucesso" (1) /* -=-=-=-=-= exemplo =-=-=-=-=- */ O valor de retorno do comando "cd /usr" foi 0 portanto foi executado com sucesso, j o retorno de "cd /dir_invalido" foi 1 porque ocorreu um erro. Agora repare no final que mesmo com um "cd /usr" continuo no diretrio HOME (~). Isto prova que um shell script usa um shell a parte (shell "filho") e no o shell que chama o script (shell pai). (Chato ficar lendo isso toda hora n? Esta foi a ltima vez! :P)

4.1.1. test ---Para fazer testes mais arrojados usamos o comando "test". A maneira de usar o test muda de acordo com o que estamos querendo testar. Se estamos comparando strings ou se estamos comparando nmeros, e por a vai... Existe uma sintaxe para cada tipo de interpretao que queremos dar a um dado. Por exemplo: "0001" diferente da string "1" mas o valor numrico igual. E por isso usamos sintaxes diferentes, para que o comando saiba que tipo de comparao estamos fazendo. Continue lendo... --> expresses com strings: O sinal de "=" verifica se a primeira string igual a segunda; o "!=" verifica se a primeira string diferente da segunda; o parmetro "-z" verifica se a string vazia; e o parmetro "-n" verifica se a string NO vazia.

/* -=-=-= exemplos =-=-=- */ $ test "abcd" = "abcd"; echo $? 0 $ test "abcd" != "abcd"; echo $? 1 $ test "abcd" = "efgh"; echo $? 1 $ test "abcd" != "efgh"; echo $? 0 $ test -z "meleu"; echo $? 1 $ test -n "meleu"; echo $? 0 $ test -n ""; echo $? 1 $ test -z ""; echo $? 0 /* -=-=-= exemplos =-=-=- */ Uma maneira mais prtica de usar o "test" e subistitu-lo pelos [colchetes]. muito mais prtico e bonitinho :P $ test "meleu" = "$nome" o mesmo que fazer: $ [ "meleu" = "$nome" ] Muito melhor, no acham?! Vamos usar esta notao a partir de agora! Agora vamos a uma dica til pra hora de fazer comparaes entre strings. Primeiro vamos a um exemplo e depois a uma explicao. /* -=-=-=-=-= exemplo =-=-=-=-=- */ $ cat strcmp1.sh #!/bin/bash if [ $1 = $2 ]; then echo As strings so iguais. fi $ ./strcmp1.sh meleu ./strcmp.sh: [: meleu: unary operator expected /* -=-=-=-=-= exemplo =-=-=-=-=- */ Note que o test deu um erro, e por isso retornou um no-zero para o if. Observe o seguinte: /* -=-=-=-=-= exemplo2 =-=-=-=-=- */ $ cat strcmp2.sh #!/bin/bash if [ $1 = $2 ]; then echo As strings so iguais. else echo As strings so diferentes. fi

$ ./strcmp2.sh meleu ./strcmp.sh: [: meleu: unary operator expected As strings so diferentes. /* -=-=-=-=-= exemplo2 =-=-=-=-=- */ Aconteceu a mesma coisa que no primeiro exemplo, s que agora temos um else pra ser executado caso a expressao do if retorne falso (ou no-zero). Uma soluo pra que no d este erro no test usar aspas duplas. Veja s: /* ------------------ */ BashScript/strcmp.sh #!/bin/bash if [ "$1" = "$2" ]; then echo As strings so iguais. else echo As strings so diferentes. fi /* ------------------ */ Com este acontece tudo certo. ;) Voc tambm NO deve escrever tudo junto, assim: $1=$2 ou "$1"="$2" Desta maneira o test vai retornar sempre verdadeiro, pois seria como se voc estivesse passado somente um parmetro para ele. --> expresses com arquivos O parmetro "-e" verifica se um arquivo regular; o "-d" verifica se um diretrio; e o "-x" verifica se o arquivo executvel. Obviamente se o arquivo no existir ocorrer um erro. /* -=-=-= exemplo $ [ -f /bin/ls ]; 0 $ [ -d /bin/ls ]; 1 $ [ -x /bin/ls ]; 0 /* -=-=-= exemplo =-=-=- */ echo $? echo $? echo $? =-=-=- */

Lgico que no existem s esses trs! Consulte a pgina man do test que voc ver muitos outros parmetros para expresses com arquivos. --> expresses aritmticas Aqui bem diferente das linguagens de programao comuns... No podemos utilizar os operadores que estamos acostumados, como '=' para igual, ' /dev/null &

Chega de moleza! Se quiser saber mais leia a man page do dialog! ;)

-------------------------------------------------------------------------

8. Coisas teis de se aprender *************************** No basta saber somente sobre o bash! Existem muitas outras coisas fora do bash que voc deve usar pra aumentar o poder dos seus scripts. O meu pblico-alvo so os fuadores e como tais eles no podem ter preguia de ler as manpages. Vai l cara... a manpage uma grande amiga! ;-) Aqui vai uma lista do que seria bom de voc aprender, o que est marcado com um asterisco quer dizer que muito til de aprender: + Linguagens: awk; *Expresses Regulares (ERs);

+ Comandos: *grep; *sed; *cut; tr; paste; sort; uniq; bc; *expr; *wc; eval (na manpage do bash); trap (idem); comm; join; netcat e lynx (ambos so muito teis se voc quer fazer scripts que usem o que a rede tem a nos oferecer. o netcat, vulgo nc, pode ser encontrado em ). Cara... sabendo tudo isso, voc j ser um iniciado. A partir da o que manda a experincia, prtica, prtica e prtica. Muita prtica! Um dia eu ainda chego a esse nvel... Eu sei que est na lista ali em cima, mas vale salientar: ERs, grep e sed so REALMENTE MITO TEIS!!!

-------------------------------------------------------------------------

9. Exemplos Variados ***************** verdade que so poucos exemplos. Eu poderia ficar "enxendo lingia" metendo vrios exemplos aqui e dizer que escrevi quatro mil linhas de texto, mas acho que no seria uma boa... Se voc quer mais exemplos olhe as Referncias (principalemente no Adv-Bash-Scr-HOWTO), entre na lista de discusso... enfim: se vire!

9.1. backup.sh ========= /* ----------------- */ BashScript/bacanas/backup.sh #!/bin/bash # OBS.: Por favor melhore este script! :-) # Se o nmero de parmetros for menor que 2... [ $# -lt 2 ] && { echo "Uso: `basename $0` destino origem [origem2 origem3...]" exit 1 # ... sai do script } echo "--> Fazendo backup" FILE="${1}_$(/bin/date +%d-%m-%Y).tgz" shift # Aqui est o "segredo": o shift acima executado para que eu possa # usar "$*" no if abaixo. if tar czf $FILE $* ; then echo "--> Backup feito com sucesso" else echo "--> OCORREU UM ERRO houve um erro ao tentar extrair '$FILE'" echo -e " este arquivo ser ignorado.$N" unset FILE fi ;; '') unset FILE ;; *) [ "$FILE" ] && { IFS= echo "$LINHA" >> $FILE } ;; esac done echo "--> Fim