|
|
| Este artigo está disponível em: English Castellano Deutsch Francais Nederlands Portugues Turkce |
por Katja and Guido Socher <katja(at)linuxfocusorg, guido(at)linuxfocus.org> Sobre o autor: 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. Traduzido para Português por: Patrick Carpalhoso <carpalhoso(at)mail.telepac.pt> Conteúdo: |
Abstrato:
Neste
artigo iremos explicar como escrever pequenos scripts shell e dar vários
exemplos.
#!/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 " $mailfolder
O 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
done
Como 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 $filen
Como 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.
|
|
Páginas Web mantidas pelo time de Editores LinuxFocus
© Katja and Guido Socher, FDL LinuxFocus.org Clique aqui para reportar uma falha ou para enviar um comentário para LinuxFocus |
Informação sobre tradução:
|
2002-04-23, generated by lfparser version 2.27