original in en Katja and Guido Socher
en to pt Patrick Carpalhoso
Katja é a editora germânica de LinuxFocus. Ela gosta de Tux, filmes & fotografia e o mar. A sua página pessoal encontra-se aqui.
Guido é um fan de Linux desde a muito e gosta do Linux porque ele foi criado por pessoas honestas e de mentalidade aberta. É uma das razões porque o chamamos open source. A sua página pessoal esta no linuxfocus.org/~guido.
#!/bin/shOs caracteres #! informam o sistema que o primeiro argumento que segue na linha é o programa utilizado para executar este ficheiro. Neste caso /bin/sh é o shell que utilizamos.
variável=valorPara ler o conteúdo de uma variável basta colocar um cifrão antes da variável;
#!/bin/sh # atribui um valor: a="hello world" # e agora escreve o conteúdo de "a": echo "A é:" echo $aEscreva estas linhas no seu editor de texto e grave com o nome first. Ponha o script executável escrevendo chmod +x first no shell e executa escrevendo ./first
A é: hello worldPor vezes é possível confundir os nomes das variáveis com o resto do texto:
num=2 echo "isto é o $numnd"Isto não vai imprimir "isto é 2nd" mas "isto é " porque o shell vai procurar por uma variável chamada numnd que não tem valor nenhum. Para dizer ao shell que estamos a fazer referência a variável num temos que usar as chavetas:
num=2 echo "isto é o ${num}nd"Desta forma vai escrever: isto é o 2nd
Syntax de comandos | Objectivo |
---|---|
echo "algum texto" | escreve algum texto no ecrã |
ls | lista ficheiros |
wc -l ficheiro wc -w ficheiro wc -c ficheiro |
conta as linhas num ficheiro ou conta o numero de palavras conta os numeros caracteres |
cp ficheiroorigem ficheirodestino | copia ficheiroorigem para ficheirodestino |
mv nomeantigo novonome | renomeia ou move um ficheiro |
rm ficheiro | apaga um ficheiro |
grep 'qualquercoisa' ficheiro | procura por strings num ficheiro Exemplo: grep 'qualquercoisa' ficheiro.txt |
cut -b colnum file | extrai dados de uma coluna fixa de texto Exemplo: extrai caracteres da posição 5 a 9 cut -b5-9 file.txt Não confundir com o comando "cat" que faz uma coisa completamente diferente |
cat ficheiro.txt | escreve o conteúdo de ficheiro.txt no stdout (seu ecrã) |
file ficheiroqualquer | descreve qual é o tipo do ficheiro ficheiroqualquer |
read var | pede ao utilizador para escrever e coloca numa variável (var) |
sort ficheiro.txt | ordena as linhas no ficheiro.txt |
uniq | remove as linhas duplicadas, utilizado em combinação com sort visto
uniq remover unicamente linhas duplicadas consecutivas Exemplo: sort ficheiro.txt | uniq |
expr | faz matemática no shell Exemplo: adiciona 2 e 3 expr 2 "+" 3 |
find | procura ficheiros Exemplo: procura por nome: find . -name ficheiro -print Este comando tem muitas possibilidades e opções. É demasiado para ser explicado ao pormenor neste artigo. |
tee | escreve os dados para stdout (seu ecrã) e para um ficheiro Normalmente utilizado da seguinte forma: umcomando | tee ficheiroout Ele escreve o output de umcomando para o ecrã e para o ficheiro ficheiroout |
basename ficheiro | devolve o nome do ficheiro de um determinado ficheiro e remove o
caminho Exemplo: basename /bin/tux devolve unicamente tux |
dirname ficheiro | devolve unicamente o nome da directoria de um determinado nome e
remove o nome do ficheiro Exemplo: dirname /bin/tux devolve unicamente /bin |
head ficheiro | escreve umas linhas desde o inicio do ficheiro |
tail file | escreve umas linhas desde o fim do ficheiro |
sed | sed é basicamente um programa de pesquisa e substituição. Ele lê
texto de um input standard (ex desde um pipe) e escreve o resultado para stdout
(normalmente o ecrã). O padrão de pesquisa é uma expressão regular (ver
referências). Esse padrão de pesquisa não deve ser confundido com a syntax da
wildcard do shell. Para substituir a string linuxfocus por LinuxFocus num
ficheiro texto faça: cat ficheiro.txt | sed 's/linuxfocus/LinuxFocus/' > novoficheiro.txt Isto substitui a primeira ocurência da string linuxfocus em cada linha com LinuxFocus. Se existirem linhas onde linuxfocus apareça varias vezes e que queira substituir todos faça: cat ficheiro.txt | sed 's/linuxfocus/LinuxFocus/g' > novoficheiro.txt |
awk | A maior parte das vezes awk é utilizado para extrair campos de uma
linha de texto. O separador por defeito é espaço. Para definir um outro utiliza
a opção -F. cat ficheiro.txt | awk -F, '{print $1 "," $3 }'Neste caso estamos a utilizar a virgula (,) como separador de campos e escrevemos a primeira e terceira coluna ($1 $3). Se ficheiro.txt tiver linhas como: Adam Bor, 34, India Kerry Miller, 22, USAira dar como resultado: Adam Bor, India Kerry Miller, USAO awk permite fazer muita mais coisas mas esta é a utilização mais frequente. |
grep "hello" ficheiro.txt | wc -lprocura as linhas com a string hello no ficheiro.txt e conta as linhas.
find . -mtime -1 -type f -printprocura todos os ficheiros que foram modificados nas ultimas 24 horas (-mtime -2 significaria 48 horas). Se você quer armazenar esse ficheiros num arquivo tar (ficheiro.tar) a syntax para o tar teria de ser:
tar xvf ficheiro.tar ficheiro1 ficheiro2 ...Em vez de escrever isso tudo, você pode combinar 2 comandos (find e tar) utilizando backticks. Tar ira aquivar todos os ficheiro que find escreveu:
#!/bin/sh # Backticks (`) não plicas ('): tar -zcvf ultimamod.tar.gz `find . -mtime -1 -type f -print`
if ....; then .... elif ....; then .... else .... fiA maior parte das vezes um comando especial chamado test é utilizado dentro de uma instrução if. Ele pode ser utilizado para comparar strings ou testar se um ficheiro existe, se ele pode ser lido etc...
[ -f "umficheiro" ] : Testa se umficheiro é um ficheiro. [ -x "/bin/ls" ] : Testa se /bin/ls exista e se é um executável. [ -n "$var" ] : Testa se a the variável $var tem algo. [ "$a" = "$b" ] : Testa se as variáveis "$a" e "$b" são iguaisExecuta o comando "man test" para obter uma longa lista de todos os tipos de operadores de teste para comparações e ficheiros.
#!/bin/sh if [ "$SHELL" = "/bin/bash" ]; then echo "o seu shell de login é o bash (bourne again shell)" else echo "o seu shell de login não é bash mas sim $SHELL" fiA variável $SHELL contêm o nome do shell de login e ela é testada que é comparada com a string "/bin/bash"
[ -f "/etc/shadow" ] && echo "Este computador utiliza shadow passwords"Os && podem ser utilizados como uma curta instrução if. A parte direita é executada se a parte esquerda for verdadeira. Pode ler isso como AND. Desta maneira o exemplo é: "O ficheiro /etc/shadow exista AND o comando é executada". O operador OR (||) esta também disponível. Segue um exemplo:
#!/bin/sh mailfolder=/var/spool/mail/james [ -r "$mailfolder" ] || { echo "Não pode ler $mailfolder" ; exit 1; } echo "$mailfolder têm um mail de:" grep "^From " $mailfolderO script testa em primeiro se ele pode ler o mailfolder. Se for o caso ele escreve a linha "têm um mail" no folder, Se ele não conseguir ler o ficheiro $mailfolder então o operador OR entra em acção. Em Inglês você pode ler "Mailfolder readable or exit program". O problema aqui é que têm de ter exactamente um comando atras do OR mas precisamos de 2:
case ... in ...) faz qualquer coisa aqui;; esacVejamos um exemplo. O comando file pode testar qual é o tipo de um ficheiro:
file lf.gz devolve: lf.gz: gzip compressed data, deflated, original filename, last modified: Mon Aug 27 23:09:18 2001, os: UnixVamos utilizar isto agora para escrever um script chamado smartzip que pode descomprimir bzip2, gzip and zip ficheiros comprimidos automaticamente:
#!/bin/sh ftype=`file "$1"` case "$ftype" in "$1: Zip archive"*) unzip "$1" ;; "$1: gzip compressed"*) gunzip "$1" ;; "$1: bzip2 compressed"*) bunzip2 "$1" ;; *) error "Ficheiro $1 no pode ser descomprimido com smartzip";; esac
select var in ... ; do break done .... agora $var pode ser utilizado ....Vejamos este exemplo:
#!/bin/sh echo "Qual é o seu SO preferido ?" select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do break done echo "Você seleccionou $var"O que script faz:
Qual é o seu SO preferido ? 1) Linux 2) Gnu Hurd 3) Free BSD 4) Other #? 1 Você seleccionou LinuxNo shell você têm as seguintes instruções de ciclos disponíveis:
while ...; do .... doneO ciclo-while sera executada até que a expressão que estamos a testar ser verdadeira. A palavra-chave "break" pode ser utiliza para abandonar um ciclo a qualquer altura. Com a palavra-chave "continue" o ciclo continua com a proxima iteração e ignora o resto do corpo do ciclo.
for var in ....; do .... doneO que sega ira imprimir as letras de A a C no ecrã:
#!/bin/sh for var in A B C ; do echo "var é $var" doneUm outro exemplo de script util, chamado showrpm, print uma lista do conteúdo de um pacote RPM:
#!/bin/sh # lista um resumo do conteúdo de um pacote RPM UTILIZAÇÃO: showrpm rpmficheiro1 # rpmficheiro2 ... EXEMPLO: showrpm /cdrom/RedHat/RPMS/*.rpm for rpmpackage in $*; do if [ -r "$rpmpackage" ];then echo "=============== $rpmpackage ==============" rpm -qi -p $rpmpackage else echo "ERRO: não consegue ler o ficheiro file $rpmpackage" fi doneComo pode ver a variável especial, $* que contêm todos os argumentos da linha de comando. Se você executar
#!/bin/sh echo *.jpgIsto ira escrever "mail.jpg tux.jpg".
#!/bin/sh echo "*.jpg" echo '*.jpg'Isto ira escrever "*.jpg" 2 vezes.
#!/bin/sh echo $SHELL echo "$SHELL" echo '$SHELL'Isto ira escrever:
/bin/bash /bin/bash $SHELLE por fim exista a possibilidade de aceitar significado especial de qualquer caracter fazendo preceder da backslash:
echo \*.jpg echo \$SHELLIsto ira escrever:
*.jpg $SHELLAqui documentos
#!/bin/sh # Temos menos de 3 argumentos. Escreve o texto do help: if [ $# -lt 3 ] ; then cat <<HELP ren -- renomeia um numero de ficheiros utilizando expressões do sed UTILIZAÇÃO: ren 'regexp' 'replacement' files... EXEMPLO: renomeia todos os ficheiros *.HTM para *.html: ren 'HTM$' 'html' *.HTM HELP exit 0 fi OLD="$1" NEW="$2" # O comando shift remove um argumento da lista dos argumentos da linha de # comandos. shift shift # $* agora tem todos os ficheiros: for file in $*; do if [ -f "$file" ] ; then newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"` if [ -f "$newfile" ]; then echo "ERROR: $newfile já existe" else echo "renomeando $file para $newfile ..." mv "$file" "$newfile" fi fi doneÉ o script mais complexo que vimos até aqui. Vamos falar um pouco sobre ele. A primeira instrução if testa se temos ao menos 3 parâmetros na linha de comandos. (A variável especial $# contém o numero de argumentos). Se não for o caso, o texto do help é enviado ao comando cat que por sua vez mande-o para o ecrã. Depois de escrever o texto do help saímos do programa. Se tivermos 3 ou mais argumentos vamos atribuir o primeiro argumento a variável OLD e o segundo a variável NEW. A seguir deslocamos os parâmetros da linha de comandos 2 vezes para colocar o terceiro argumento na primeira posição de $*. Com $* entramos no ciclo for. Cada um dos argumentos em $* é atribuído um a um a variável $file. Aí vamos em primeiro testar se o ficheiro existe realmente e vamos construir um novo nome de ficheiro utilizando find e sed. Os backticks são utilizados para atribuir o resultado para a variável newfile. Agora temos tudo o precisamos: O antigo e novo nome do ficheiro. É o que utilizamos com o comando mv para renomear os ficheiros.
nomedafuncao() { # Dentro do corpo $1 esta o primeiro argumento dado a função No $2 esta o # segundo ... corpo }Tem de "declarar" as funções no inicio do script antes de poder utiliza-las.
#!/bin/sh # vim: set sw=4 ts=4 et: help() { cat <<HELP xtitlebar -- muda o nome de um xterm, gnome-terminal ou kde konsole UTILIZAÇÃO: xtitlebar [-h] "texto_para_a_janela" OPÇÕES: -h help text EXEMPLO: xtitlebar "cvs" HELP exit 0 } # Se ocorrer algum erro ou se for introduzido -h chamamos a função help: [ -z "$1" ] && help [ "$1" = "-h" ] && help # Envia a sequência de escape que muda o titulo da barra xtem: echo -e "\033]0;$1\007" #É um bom habito de ter sempre uma ajuda extensiva dentro dos scripts. Isto torna possível para os outros (e você) utilizar e perceber o script.
#!/bin/sh help() { cat <<HELP Isto é uma demo de um analisador de comando. EXEMPLO DE UTILIZAÇÃO: cmdparser -l hello -f -- -ficheiro1 ficheiro2 HELP exit 0 } while [ -n "$1" ]; do case $1 in -h) help;shift 1;; # a função help é chamada -f) opt_f=1;shift 1;; # a variável opt_f é inicializada -l) opt_l=$2;shift 2;; # -l pega num argumento -> shift por 2 --) shift;break;; # fim das opções -*) echo "erro: não exista a opção $1. -h para help";exit 1;; *) break;; esac done echo "opt_f é $opt_f" echo "opt_l é $opt_l" echo "primeiro argumento é $1" echo "2nd argumento é $2"Experimenta ! POde excuta-lo com por exemplo:
cmdparser -l hello -f -- -umficheiro1 umficheiro2Ele ira produzir
opt_f é 1 opt_l é hello primeiro argumento é -umficheiro1 2nd argumento é umficheiro2Como é que ele funciona ? Basicamente ele faz um loop pelo todos os argumentos e verifica se coincidam com a instrução case. Se ele encontrar algum que coincida ele carrega a variável e shift a linha de comando por um. A convenção unix é que as opções (coisas começando com o menos) têm de vir em primeiro. Você deve de indicar no fim da opção escrevendo dois sinais menos (--). Você precisa, com grep por exemplo, pesquisar uma string que começa com o sinal menos:
Procura de -xx- no ficheiro f.txt: grep -- -xx- f.txtO nosso option parser pode manipular os -- também como pode ver na listagem acima.
cp framework.sh myscripte inserir a actual funcionalidade dentro de "myscript".
#!/bin/sh # vim: set sw=4 ts=4 et: help() { cat <<HELP b2h -- converte binário para decimal UTILIZAÇÃO: b2h [-h] binarynum OPÇÕES: -h help text EXEMPLO: b2h 111010 retorna 58 HELP exit 0 } error() { # escreve um erro e sai echo "$1" exit 1 } lastchar() { # devolve o ultimo caracter de uma string no $rval if [ -z "$1" ]; then # string vazia rval="" return fi # wc coloca algum espaço atras o output é por caso disso que necessitamos # de sed: numofchar=`echo -n "$1" | wc -c | sed 's/ //g' ` # agora corta o ultimo caractero rval=`echo -n "$1" | cut -b $numofchar` } chop() { # remove o ultimo caracter numa string and retorno dentro de $rval if [ -z "$1" ]; then # string vazia rval="" return fi # wc coloca algum espaço atras o output é por caso disso que necessitamos # de sed: numofchar=`echo -n "$1" | wc -c | sed 's/ //g' ` if [ "$numofchar" = "1" ]; then # unicamente um caracter na string rval="" return fi numofcharminus1=`expr $numofchar "-" 1` # agora corta tudo mas o ultimo caractero: rval=`echo -n "$1" | cut -b 0-${numofcharminus1}` } while [ -n "$1" ]; do case $1 in -h) help;shift 1;; # função help é chamada --) shift;break;; # fim das opções -*) error "erro: no such option $1. -h for help";; *) break;; esac done # O programa principal sum=0 weight=1 # Têm de ser dado um argumento: [ -z "$1" ] && help binnum="$1" binnumorig="$1" while [ -n "$binnum" ]; do lastchar "$binnum" if [ "$rval" = "1" ]; then sum=`expr "$weight" "+" "$sum"` fi # remove a ultima posição no $binnum chop "$binnum" binnum="$rval" weight=`expr "$weight" "*" 2` done echo "binário $binnumorig é decimal $sum" #O algoritmo utilizado neste script pega no peso decimal (1,2,4,8,16,..) de cada numero começando com o numero mais a direita e adiciona-o a soma se o número é um 1. Desta maneira "10" é:
#!/bin/sh # vim: set sw=4 ts=4 et: ver="0.1" help() { cat <<HELP rotatefile -- roda de ficheiro UTILIZAÇÃO: rotatefile [-h] ficheiro OPÇÕES: -h help text EXEMPLO: rotatefile out Isto ira renomeiar por exemplo out.2 para out.3, out.1 para out.2, out para out.1 e criar um ficheiro out vazio O numero máximo é 10 version $ver HELP exit 0 } error() { echo "$1" exit 1 } while [ -n "$1" ]; do case $1 in -h) help;shift 1;; --) break;; -*) echo "erro: no such option $1. -h for help";exit 1;; *) break;; esac done # verificação de input: if [ -z "$1" ] ; then error "ERRO: têm de especificar um ficheiro, utiliza -h para ajuda" fi filen="$1" # renomeia qualquer ficheiro .1 , .2 etc: for n in 9 8 7 6 5 4 3 2 1; do if [ -f "$filen.$n" ]; then p=`expr $n + 1` echo "mv $filen.$n $filen.$p" mv $filen.$n $filen.$p fi done # renomeia o ficheiro original: if [ -f "$filen" ]; then echo "mv $filen $filen.1" mv $filen $filen.1 fi echo touch $filen touch $filenComo funciona o programa ? Após verificação que o utilizador introduziu um ficheiro vamos para um ciclo que vai de 9 a 1. O ficheiro 9 é agora renomeado para 10, ficheiro 8 para 9 e assim por diante. Depois do ciclo renomeamos o ficheiro original para 1 e criamos um ficheiro vazio com o nome do ficheiro original.
sh -x strangescriptIsto ira executar o script e mostrar todos as instruções que são executadas com as variáveis e wildcards já expandido.
sh -n o_scriptSe não retornar nada então o seu programa esta sem erros de sintaxe.