Programação em Bourne-Again Shell (BASH)

Embed Size (px)

Citation preview

.----------------------------------. | Programao em Bourne-Again Shell `------------------------------------, | Por MELEU http://meleu.da.ru 05/2002 |

`------------------------------------------------------------------------'

-=< NDICE >=-

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 meleu users drwxr-xr-x 2 meleu users drwxr-xr-x 2 meleu users 4096 Aug 18 15:28 GNUstep 4096 Aug 19 23:11 progs 4096 Aug 19 22:57 txts

/* -=-=-=-=-=-= debugar =-=-=-=-=-=- */

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

no executa os comandos, apenas verifica erros de sintaxe (noexec);

-v

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:

* 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; E 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 $ echo $SHLVL 2 $ exit exit $ echo $SHLVL 1 /* -=-=-= exemplo =-=-=- */ # sa do segundo bash # estou executando o bash a partir do bash

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)# quantos digitos tem?

while [ $CONT -lt 8 ]; do NUM=${NUM}0

# se nao tiver 8 digitos acrescenta 0's

CONT=$(echo -n $NUM | wc -c) 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.

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:interactivecomments: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

o nome do shell script (a.k.a. parmetro zero);

$1 a $9

$1 o primeiro parmetro, $9 o nono, e assim por diante;

${10}, ${11}...

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).

Outros:

$?

valor de retorno do ltimo comando (explicado mais adiante);

$$

PID do script.

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 uma boa rede de irc $ $ # 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 que conheco eh irc.linux.org"

que conheco eh

irc.linux.org

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 | Negrito |0|

| 1 | Vermelho | 1 | |2| |3|

| Cor X para o primeiro plano | 3X | Verde | Cor X para o segundo plano | 4X | Marrom | Sublinhado | Piscando (blink) | Vdeo reverso | -x| 4 | Azul | 5 | Roxo | 7 | Ciano | -- | Branco |7| |4| |5| |6|

'-----------------------------'----'-------------'---'

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 "read" vai ler apenas uma varivel, toda a string vai ser atribuda a esta varivel. Quando vai ler mais de uma varivel ele atribui cada string a sua respectiva varivel; e quando o nmero de strings excede o nmero de 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 meleu hack root $ # "echo" nao le arquivo, ele usa argumentos. $ # A linha abaixo nao tem utilidade. $ who | cut -c0-9 | echo # lembrando: pipe transforma stdout em stdin

$ # "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 ]; echo $? 0 $ [ -d /bin/ls ]; echo $? 1 $ [ -x /bin/ls ]; echo $? 0 /* -=-=-= exemplo =-=-=- */

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, '&2 exit 1 fi /* ----------------- */

9.2. howto.sh ========

/* ----------------- */ BashScript/bacanas/howto.sh #!/bin/bash # # ********************************************* # * Script para visualizar HOWTOs rapidamente * # *********************************************

# # #

http://meleu.da.ru meleu

# Inspirado em um outro script que vi no Tips-HOWTO. # O script do Tips-HOWTO era muito simples, fiz algumas # modificaes que so interessantes para ns que falamos # portugus e de vez em quando temos uns HOWTOs traduzidos, # e ainda fiz um "suporte" aos mini-HOWTOs. ;-) # E mais: se voc no lembra direito do nome do HOWTO, pode # passar apenas a(s) primeira(s) letra(s) e/ou usar os curingas # ('*', '?' e '[]'), mas aconselha-se, neste ltimo caso, o uso de # aspas ("quoting") para evitar que seja passado como parmetro(s) # o contedo do diretrio atual. Caso ele encontre mais de um # arquivo para a expresso voc poder escolher atravs da tela que # aparecer. # Exemplos: # [prompt]$ howto Net # [prompt]$ howto "*[Bb]ash" # [prompt]$ howto "*Prog" # # Se voc ainda no tem e no sabe onde pegar HOWTOs traduzidos # procure em http://ldp-br.conectiva.com.br # # Pr-requisitos para o script funcionar direitinho (ou seja, sem # precisar de alteraes): # + os HOWTOs devem estar em "/usr/doc/Linux-HOWTOs"; # + os HOWTOs em portugus devem estar em "/usr/doc/Linux-HOWTOs.pt";

# + os mini-HOWTOs devem estar em "/usr/doc/Linux-mini-HOWTOs"; # + todos os [mini-]HOWTOs[.pt] devem estar gzipados, se os seus no # # # # # Se voc testou o script, ele funcionou direitinho e voc gostou, # ento digite "cp howto.sh /usr/local/bin/howto" para que todos do # seu sistema possam utiliz-lo. ;-) # # Aproveite! esto assim basta entrar no diretrio dos HOWTOs e digitar "gzip *".

# Estes so os diretrios onde so instalados os [mini-]HOWTOs no # Slackware. Se a sua distribuio usa um diretrio diferente # mude a(s) varivel(is) a seguir. HTDIR=/usr/doc/Linux-HOWTOs miniHTDIR=/usr/doc/Linux-mini-HOWTOs PTHTDIR=/usr/doc/Linux-HOWTOs.pt # este onde eu coloco os traduzidos

# Variveis que indicam as cores (pra no precisar ficar # digitando os cdigos ANSI toda hora) BLUE="\e[1;34m" RED="\e[1;31m" NCOLOR="\e[m"

function Ler { zless $1 echo -e "${RED}\nTchau!\n$NCOLOR" exit }

# Funo que mostra a lista dos HOWTOs e sai do script. function Lista { ls -C $HTDIR | less echo -e " ${BLUE}Uso:$NCOLOR `basename $0` [-p | -m] nome-do-HOWTO Faa '`basename $0` -h' para ver a descrio das opes." exit 1 }

# se no for passado nenhum parmetro ele mostra a lista [ -z "$1" ] && Lista

# -------------------# - TESTA PARMETROS # -------------------case $1 in

# - mensagem de ajuda -

# ---------------------h) echo -e " ${RED}--[ Lista de opes ]--$NCOLOR -p \t HOWTOs em portugus -m \t mini-HOWTOs -h \t imprime esta mensagem " exit # depois da mensagem de ajuda, sair ;;

# - HOWTOs em portugus # -----------------------p) HTDIR=$PTHTDIR [ -z "$2" ] && Lista shift # Lembra do 'shift'? Aqui ele faz com que o primeiro # parmetro deixe de ser '-p' para ser o nome-do-HOWTO ;;

# - mini-HOWTOs # ---------------m) HTDIR=$miniHTDIR [ -z "$2" ] && Lista shift # mesma funo do shift no '-p' ;;

esac

# Ao fim deste case $1 tem necessariamente o nome ou a(s) # primeira(s) letra(s) do nome do HOWTO a ser procurado.

cd $HTDIR

FILE=`ls $1*.gz 2>/dev/null`

[ `echo $FILE | wc -w` -gt 1 ] && { PS3="Entre com o nmero: " select opc in $FILE Sair ; do

[ "$opc" = "Sair" ] && exit

for HOWTO in $FILE ; do [ "$opc" = "$HOWTO" ] && Ler $HOWTO done done }

[ -e "$FILE" ] && Ler $FILE

# Isto s ser executado se no for encontrado o HOWTO echo -e "${RED}* * * HOWTO no encontrado * * *$NCOLOR" echo "Tente '`basename $0` [-p | -m]' para ver a lista" exit 1

#-==

/* ----------------- */

9.3. todo.sh =======

/* ----------------- */ BashScript/bacanas/todo.sh #!/bin/bash

PROG=`basename $0` EDITOR=`which vi` FILE="$HOME/.ToDo" USAGE="Uso: $PROG [-h|-e]"

case $1 in -h) echo " $USAGE

-e -h

edita a lista de \"Para Fazer\" (To Do) imprime esta mensagem e sai

Sem parmetros $PROG ir mostrar a lista de \"To-Do\". " exit ;;

-e) $EDITOR $FILE exit ;;

'') cat $FILE 2> /dev/null || { echo "Voc precisa criar o arquivo $HOME/.ToDo !" echo "Entre \"$PROG -e\" para editar seu ~/.ToDo" echo "Para ajuda tente \"$PROG -h\"" exit 1 } ;;

*) echo "Parmetro \"$1\" desconhecido!" echo "$USAGE" echo "Entre com \"$PROG -h\" para ajuda." exit ;;

esac /* ----------------- */

9.4. inseretxt.sh =========

/* ----------------- */ BashScript/bacanas/inseretxt.sh #!/bin/bash

# # Muitas vezes durante a escrita do texto # "Programao em Bourne-Again Shell" eu precisava # inserir um cdigo de um script numa determinada # posio do arquivo e esta posio ficava entre # muito texto antes e depois dessa linha. # Para fazer isso de uma maneira mais cmoda, eu # escrevi este script. # # Para informaes sobre o uso tente o parmetro '-h' ou # '--help'. # Se voc passar como o parmetro "linha" um nmero maior # que o de linhas total do "ArqOriginal" os "arquivosN" # sero inseridos no final do "ArqOriginal". # # Ah! Lembre-se de uma coisa: "linha" precisa ser um # inteiro positivo. E lembre-se de mais uma coisa: 0 # no um nmero positivo. ;-) # # meleu. #

B="\e[1m" N="\e[m" USO="Uso: `basename $0` linha ArqOriginal arquivo1 [arquivoN ...]" AJUDA="Tente \"`basename $0` --help\" para ajuda"

[ "$1" = '-h' -o "$1" = '--help' ] && { echo -e " ${B}Insere o contedo de arquivo(s) dentro de um outro.$N

$USO

Onde: \"linha\" a linha onde o texto ser inserido

\"ArqOriginal\" o arquivo que receber os textos \"arquivoN\" so os arquivos que sero inseridos em ArqOriginal " exit }

[ $# -lt 3 ] && { echo -e ${B}Erro: erro na passagem de parmetros$N echo $USO echo $AJUDA exit -1 }

Linha=$1 # verificando se $Linha um nmero inteiro positivo [ `expr $Linha - 1 2>/dev/null` -ge 0 ] 2>/dev/null || { echo -e ${B}Erro: O primeiro parmetro precisa ser inteiro positivo$N echo $AJUDA

exit 1 }

ArqOriginal=$2 [ -f $ArqOriginal ] || { echo -e ${B}Erro: \"$ArqOriginal\" no existe ou no um arquivo regular$N echo $AJUDA exit 2 }

function ApagarSair { rm "$1" exit $2 }

shift 2 Temp=/tmp/`basename $ArqOriginal`-$$.tmp

# --> incio do arquivo original: head -$[$Linha-1] $ArqOriginal > $Temp

# --> arquivos que sero inseridos: ContaAcerto=0 for Arq in "$@"; do [ -f "$Arq" ] || {

echo -e ${B}OBS.: \"$Arq\" no existe ou no um arquivo regular$N continue } cat $Arq >> $Temp (( ContaAcerto++ )) done [ $ContaAcerto -eq 0 ] && { echo -e ${B}Nenhum arquivo foi inserido em \"$ArqOriginal\"$N ApagarSair $Temp 3 } echo

# --> pra terminar, final do arquivo original: sed -n "$Linha,\$p" $ArqOriginal >> $Temp

ArqFinal="$ArqOriginal.new" [ -e $ArqFinal ] && { echo -e ${B}J existe um arquivo chamado \"$ArqFinal\".$N read -n 1 -p "Deseja sobregrav-lo? (s/N) " SN echo [ "$SN" != 'S' -a "$SN" != 's' ] && { echo -e "$B\nOperao cancelada!$N" ApagarSair $Temp 3 } }

cat $Temp > $ArqFinal

echo -e " ${B}Operao concluda com sucesso.$N Confira em \"$ArqFinal\" "

ApagarSair $Temp

/* ----------------- */

9.5. Mextract.sh ===========

/* ----------------- */ BashScript/bacanas/Mextract.sh #!/bin/sh # # **************************** # * Meleu Extraction Utility * # **************************** # # # Este script baseado no Phrack Extraction Utility, (mais informaes http://meleu.da.ru

# ). Fiz ele, primeiro para praticar, segundo para # servir como mais um exemplo no texto "Programao em Bourne-Again Shell", # e ltimo para extrao dos cdigos do texto. =P # ############# Se j existirem arquivos com o nome dos que sero extrados # !CUIDADO! # eles sero sobregravados! Portanto, se voc extrair uma vez, ############# alterar o(s) cdigo(s) extrado(s) e extrair novamente, # # # # A seguir eu vou comentar sobre o cdigo fazendo referncia aos tpicos # do texto "Programao em Bourne-Again Shell". # # # + A funo do IFS explicada no tpico "2.2. Variveis do Shell", # neste script eu usei o IFS com valor nulo (vazio) para que os comandos # considerem espaos que vm antes de qualquer caractere como parte do # dado. Se voc fizer por exemplo "read var" e antes de entrar qualquer # coisa colocar espaos e/ou TAB, voc ver que eles sero desconsiderados # se o IFS tiver seu valor default (espao, TAB, newline); # # + A opo -r no read (explicada em 3.2. read) serve para ignorar o # poder que a contra-barra (backslash) tem de "escapar" os caracteres. Em # outras palavras: a opo -r garante que quando o read receber uma # contra-barra ela ser passada para a varivel sem nenhum valor especial; # # + O cat enviando os dados para o read do while explicado em perder as alteraes feitas!

# "5.5. Redirecionando loops" sob o ttulo de "pipeando para o while"; # # + o set usado para fazer com que cada palavra (palavra aqui tem um # sentido de conjunto de caracteres separados por aqueles definidos no # IFS) vire um parmetro posicional, conforme explicado em # "2.4.2. set (para editar parmetros posicionais)". A opo -- quer dizer # "acabaram as opes, o que vier a partir daqui so os valores dos # parmetros de posio", esta opo serve para prevenir que alguma # informao que comece com o caractere - seja considerado uma opo # sendo passada para o set; # # + No tpico "2.5. Substituio de Variveis" voc ver a explicao # de se usar "FILE=${FILE:-.}/$1"; # # + Bom... acho que isso. Leia o cdigo, execute-o, faa testes, # mude o cdigo, execute-o novamente, veja o que mudou nos resultados, # leia as manpages em caso de dvidas... Enfim, use o mtodo hacker de # aprender a programar! ;-) # # # Espero que curta! # meleu # # P.S.: Quer um "dever de casa"? Altere o cdigo para que ele verifique # # # se j existe arquivos com o mesmo nome dos que esto prestes a serem extrados. Se existir, alertar o usurio sobre isso. Tente tambm fazer meios de deteco dos possveis erros que possam

# # #

ocorrer... Ah, sei l! Brinque com o cdigo um pouco! =)

B="\e[1m" N="\e[m"

[ $# -lt 1 ] && { echo -e "${B}Erro: falta parmetros$N" echo "Uso: `basename $0` arquivo1 [arquivoN]" exit 1 }

[ -w . ] || { echo -e "${B}Erro: voc no tem permisso de escrita neste diretrio$N" exit 1 }

OldIFS="$IFS" IFS= cat $@ | while read -r LINHA ; do IFS="$OldIFS"

set -- $LINHA case "$1" in

'') TempIFS="$IFS" IFS=/ set -- $2 IFS="$TempIFS" while [ $# -gt 1 ]; do FILE=${FILE:-.}/$1 [ -d $FILE ] || mkdir $FILE shift done FILE="${FILE:-.}/$1" if echo -n 2>/dev/null > $FILE ; then echo "* Extraindo $FILE" else echo -e "$B--> 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