(exercícios resolvidos)
A seguir, vários comandos, expressões regurales, metacaracteres, curingas para avaliar o conhecimento em shell script.
Comandos e seu comportamento
# ls /(lista os arquivos e diretórios do "/")
# ls /*(lista os arquivos e diretórios do "/", respectivamente e o conteúdo destes diretórios, mas sem usar recursividade)
# ls */(não lista os arquivos do diretório atual, mas lista os diretórios e o conteúdo destes diretórios)
# ls * /(lista os arquivos e diretórios do diretório atual, o conteúdo destes diretórios e o conteúdo do "/")
# ls /e*(lista os arquivos e diretórios do "/" que comecem com "e", respectivamente e o conteúdo destes diretórios)
# ls /etc/[py](lista os arquivos ou diretórios chamados "p" ou "y", repectivamente e o conteúdo destes diretórios, tudo dentro do "/etc")
# ls /etc/[py]*(lista os arquivos ou diretórios que começam com "p" ou "y", repectivamente e o conteúdo destes diretórios, tudo dentro do "/etc". Exemplo: p, y, pa, pb, ya, yd, yasdb, ...)
# ls /etc/[p-y]*(lista os arquivos ou diretórios que começam com "p" até "y", repectivamente e o conteúdo destes diretórios, tudo dentro do "/etc")
# ls /etc/[acp-y]*(lista os arquivos ou diretórios que começam com "a" ou "c" ou "p" até "y", repectivamente e o conteúdo destes diretórios, tudo dentro do "/etc")
# ls /etc/[a-cp-y]*(lista os arquivos ou diretórios que começam com "a" até "c" ou "p" até "y", repectivamente e o conteúdo destes diretórios, tudo dentro do "/etc")
# ls /etc/passw?(lista arquivos ou diretórios que comecem com "passw" e termine com qualquer caractere, tudo dentro do "/etc". O "?" substituir um caractere, devendo existir um para cada interrogação)
# ls /etc/?assw?(lista arquivos ou diretórios que comecem com qualquer caractere, no meio tenha "assw" e termine com qualquer caractere, tudo dentro do "/etc")
# ls /etc/[!a-pr-z]*(lista os arquivos ou diretórios que "não" começam com "a" até "p" ou "r" até "z", repectivamente e o conteúdo destes diretórios, tudo dentro do "/etc")
# ls /etc/[g][r][o]*(lista os arquivos ou diretórios que começam com "g", "r" e "o", repectivamente e o conteúdo destes diretórios, tudo dentro do "/etc")
# ls /etc/[ag][r-t][o]*(lista os arquivos ou diretórios que tenham na sua primeira letra "a" ou "g", na segunda "r" até "t" e na terceira "o" e, também, o conteúdo destes diretórios, tudo dentro do "/etc")
# ls /etc/[!1-6]*(lista os arquivos ou diretórios que "não" começam com "1" até "6", repectivamente e o conteúdo destes diretórios, tudo dentro do "/etc")
# ls /etc/[a-z]*(lista os arquivos ou diretórios que começam com "a" até "z" minúsculo, repectivamente e o conteúdo destes diretórios, tudo dentro do "/etc")
# ls /etc/[A-Z]*(lista os arquivos ou diretórios que começam com "A" até "Z" maiúsculo, repectivamente e o conteúdo destes diretórios, tudo dentro do "/etc")
# ls /etc | wc(mostra o número de linha, palavras e caracteres listado pelo comando "ls")
# ls /etc | wc -l(mostra o número de linha listado pelo comando "ls")
# ls > /tmp/teste(desvio: será criado um arquivo "/tmp/teste" que conterá a saída padrão do "ls". Se o arquivo já existir ele será sobreescrito)
# ls > /tmp/$$(devio: será criado um arquivo "/tmp/PID" que conterá a saída padrão do "ls". Se o arquivo já existir ele será sobreescrito. O "$$" é uma variável que representa um número do Process Identification)
# ls /XXX 2> /tmp/teste(desvio: será criado um arquivo "/tmp/teste" que conterá a saída de erro padrão do "ls /XXX". Se o arquivo já existir ele será sobreescrito)
# ls /XXX 2> /tmp/x$$(desvio: será criado um arquivo "/tmp/xPID" que conterá a saída de erro padrão do "ls /XXX". Se o arquivo já existir ele será sobreescrito. O "$$" é uma variável que representa um número do Process Identification)
# ls /etc/* > /tmp/$$ 2> /tmp/x$$(devio: será criado um arquivo "/tmp/PID" que conterá a saída padrão do "ls /etc/*" e será criado um outro arquivo "/tmp/xPID" que conterá a saída de erro padrão do "ls /etc/*". Se os arquivos já existirem eles será sobreescrito. O "$$" é uma variável que representa um número do Process Identification)
# ls /etc/* >> /tmp/$$ 2>> /tmp/$$(devio: será criado um arquivo "/tmp/PID" que conterá a saída padrão do "ls /etc/*" e será criado um outro arquivo "/tmp/PID" que conterá a saída de erro padrão do "ls /etc/*". Se o arquivo já existir ele o devio vai para o final do dele. O "$$" é uma variável que representa um número do Process Identification)
# ls | tee test.txt (lista na tela o conteúdo do diretório atual e também cria um arquivo "test.txt" com este conteúdo. Se o comando "ls" possuir uma saída de erro, esses erros não iram para o arquivo "test.txt". Se o arquivo já existir, ele será sobreescrito. A diferente entre o "tee" e um ">" é que aquele [tee] mostra a saída padrão na tela também. O "tee" lê a entrada padrão, escreve isso em um arquivo e também na saída padrão)
# (cd /var ; ls)(quando se têm comandos entre parênteses significa que um outro shell será aberto, onde serão executados tais comando e depois o shell morre. Então, isso quer dizer que neste exemplo, o shell nunca saiu do diretório atual, ou seja, apesar de ter listado o conteúdo de "/var", o shell nunca foi para tal diretório)
# echo Nome do Sistema: uname -o(imprime na tela "Nome do Sistema: uname -o")
# echo Nome do Sistema: `uname -o`(imprime na tela "Nome do Sistema: GNU/Linux")
# echo Nome do Sistema: $(uname -o)(imprime na tela "Nome do Sistema: GNU/Linux")
# cat /etc/passwd | sort (mostra o conteúdo de "/etc/passwd" ordenado em ordem alfabética)
# cat /etc/passwd | sort -r(mostra o conteúdo de "/etc/passwd" ordenado inversamente em ordem alfabética)
# echo *(lista os arquivos e diretórios do diretório atual sequencialmente numa linha)
# dir=pwd ; echo $dir(atribui "pwd" a variável "dir", depois mostra na tela "pwd")
# dir=$(pwd) ; echo $dir(executa a instrução "pwd" e a atribui à variável "dir", depois mostra na tela o diretório atual)
# var=a(atribui o valor "a" a váriavel "var")
# var= a(interpretou o "a" como comando, mas não o encontrou, por causa do espaço em branco)
# var =a(interpretou o "var" como comando, mas não o encontrou, por causa do espaço em branco)
# var=a b(interpretou o "b" como comando, mas não o encontrou. Não atribui o valor "a" a váriavel "var")
# var='a b'(atribui o valor "a b" a váriavel "var". O aposto inibe a interpretação de seu interior)
# var='a b'(idem)
# var=' a b'(idem)
# var=a\ b(atribui o valor "a b" a váriavel "var". A barra invertida inibe a interpretação do caractere imediatamente posterior)
# Obs: se colacasse aspas (") em vez de aposto (') o resultado seria o mesmo. Ressaltando que a diferença entre os dois é que as aspas interpretariam o caractere cifrão ($), crase (`) e barra invertida (\).
# cat /etc/passwd | sed 's/root/adm/'(mostra na tela o conteúdo de "/etc/passwd" substituindo "s" a primeira ocorrência de "root" para "adm" de cada linha)
# cat /etc/passwd | sed 's/root/adm/g'(mostra na tela o conteúdo de "/etc/passwd" substituindo "s" todas as ocorrências de "root" para "adm" de cada linha)
# sed 's/root/adm/g' /etc/passwd(idem, pois a saída padrão do "sed" é a tela. Do mesmo modo que o "cat")
# sed 's/root/adm/' /etc/passwd > /tmp/passwd2(será colocado o conteúdo de "/etc/passwd" em "/tmp/passwd2", substituindo a primeira ocorrência de "root" para "adm" de cada linha. Se esse arquivo não existir, ele será criado. Se existir, o seu conteúdo será perdido)
Obs: nunca faça "sed 's/root/adm/' /etc/passwd > /etc/passwd", pois o seu conteúdo será perdido.
# cat /etc/passwd | sed '/false/d'(apaga "d" todas as linhas que tiver a palavra "false" do arquivo)
# cat /etc/passwd | sed '3,20d'(apaga "d" da linha 3 até a linha 20)
# cat /etc/passwd | sed '3,$d'(apaga "d" da linha 3 até a última linha "$")
# cat /etc/passwd | sed '1,3s/bin/sbin/g'(mostra na tela o conteúdo de "/etc/passwd" substituindo "s" todas as ocorrências de "bin" para "sbin" da linha 1, 2 e 3)
# cat /etc/passwd | sed 's/bin/sbin/2'(somente a segunda ocorrência do "bin" será substituída por "sbin")
# cat /etc/passwd | sed 's/ .*//'(lista mostra somente a primeira palavra de cada linha ou pelo menos até encontrar um espaço em branco. O ".*" representa qualquer caractere, sendo que ele pode aparecer uma vez, várias vezes ou não aparecer. Em outras palavras, representa qualquer sequência de caracteres)
# sed 's/ .*//' /etc/passwd(idem)
# sed 's/ .*//' < /etc/passwd(idem, o resultado será o mesmo. O sinal < avisa ao shell que a entrada padrão será um arquivo em vez do teclado)
# sed 's/ .*//' /etc/passwd > /etc/passwd.new ; mv /etc/passwd.new /etc/passwd(idem, redirecionando a saída padrão para "/etc/passwd.new" e depois o renomeando para "/etc/passwd")
# sed 's/ .*//' < /etc/passwd > /etc/passwd.new ; mv /etc/passwd.new /etc/passwd(idem)
Obs: O ".*" é a união entre o "." que representa qualquer caractere, sendo obrigatória a existência de um caractere. Já o "*" representa a existência do caractere imediatamente anterior uma vez, mais vezes ou não aparecer.
# grep SENDTO /var/spool/hylafax/* -r | less ()
# find /home/user | xargs rm -f (uma forma de remover todos os arquivos incluindo os ocultos. O comando "rm" não ver arquivos ocultos)
# find -maxdepth 1 -type f | xargs chmod a-x (maxdepth - diretória atual, ou seja, profundidade 1 e do tipo regular file. Tira a permissão de execução de todos)
Sequência
# seq 5 10 (mostra na tela uma sequência de 5 à 10 de um em em. Resultado: 5,6,7,8,9,10)
# seq 5 10 100 (mostra na tela uma sequência de 5 à 100 de dez em dez. Resultado: 5, 15, 25, 35, 45, 55, 65, 75, 85, 95)
IF (tomada de decisão)
exemplo1:
if [ -x /sbin/ifconfig ] (pergundo se o "/sbin/ifconfig" é um executável)
then (então)
echo É um executável.
else (senão)
echo Não é um executável.
fi (fim desse "if")
Obs: a tomada de decisão acima é equivalente a "if [ -x /sbin/ifconfig ]; then echo É um executável.; else echo Não é um executável.; fi" . Para obter ajuda digite "help if".
WHILE (condição)
exemplo1:
verify=n ()
while [ $verify = n ] ()
do ()
echo "Opção de Entrada: "
read option
echo "Você entrou com $option. Está correto? (y/n)"
read verify
done ()
Obs: a condição acima é equivalente a "verify=n ; while [ $verify = n ]; do echo "Opção de Entrada: "; read option; echo "Você entrou com $option. Está correto? (y/n)"; read verify; done" . Para obter ajuda digite "help while".
UNTIL (condição)
exemplo1:
n=1 ()
until [ "$n" -ge 66 ] ()
do ()
echo Digite o valor de n:
read n
done ()
Obs: a condição acima é equivalente a "n=1 ; until [ "$n" -ge 66 ]; do echo Digite o valor de n: ; read n; done" . Para obter ajuda digite "help until".
FOR ou SELECT (loop)
exemplo1:
for i in 1 2 3 4 5 (inicia um loop num sequência de 1 à 5)
do (faça)
echo $i >> teste (devia a saída padrão do valor de "n" a cada loop para o arquivo "teste")
done (feito)
Obs: o loop acima é equivalente a "for i in 1 2 3 4 5; do echo $1 >> teste; done" .
exemplo2:
for n in $(seq 1 5) (inicia um loop num sequência de 1 à 5)
do (faça)
echo $n >> teste (devia a saída padrão do valor de "n" a cada loop para o arquivo "teste")
done (feito)
Obs: o loop acima é equivalente a "for n in $(seq 1 5); do echo $n >> teste; done" . Para obter ajuda digite "help for".
FOR ou SELECT (loop com base de dados em arquivo)
exemplo1:
for i in $(cat /tmp/test.txt) (inicia um loop num sequência de 1 à 5)
do (faça)
echo $i >> teste (devia a saída padrão do valor de "n" a cada loop para o arquivo "teste")
done (feito)
Obs: o loop acima é equivalente a "for i in $(cat /tmp/test.txt); do echo "$i"; done". Para obter ajuda digite "help for".
CASE (mútiplas opções)
exemplo1:
echo Escolha a opção 1 ou 2: ()
read NUM ()
case $NUM in ()
1) ()
echo O número é 1;;
2) ()
echo O número é 2;;
*) ()
echo O número não é 1 nem 2;;
esac ()
Obs: As múltiplas opções acima são equivalentes a "echo Escolha a opção 1 ou 2: ; read NUM ; case $NUM in 1) echo O número é 1;; 2) echo O número é 2;; *) echo O número não é 1 nem 2;; esac" . Para obter ajuda digite "help case".
Argumentos usados geralmente com "if", "while" etc.
-b file = True if the file exists and is block special file.
-c file = True if the file exists and is character special file.
-d file = True if the file exists and is a directory.
-e file = True if the file exists.
-f file = True if the file exists and is a regular file
-g file = True if the file exists and the set-group-id bit is set.
-k file = True if the files' "sticky" bit is set.
-L file = True if the file exists and is a symbolic link.
-p file = True if the file exists and is a named pipe.
-r file = True if the file exists and is readable.
-s file = True if the file exists and its size is greater than zero.
-s file = True if the file exists and is a socket.
-t fd = True if the file descriptor is opened on a terminal.
-u file = True if the file exists and its set-user-id bit is set.
-w file = True if the file exists and is writable.
-x file = True if the file exists and is executable.
-O file = True if the file exists and is owned by the effective user id.
-G file = True if the file exists and is owned by the effective group id.
file1 –nt file2 = True if file1 is newer, by modification date, than file2.
file1 ot file2 = True if file1 is older than file2.
file1 ef file2 = True if file1 and file2 have the same device and inode numbers.
-z string = True if the length of the string is 0.
-n string = True if the length of the string is non-zero.
string1 = string2 = True if the strings are equal.
string1 != string2 = True if the strings are not equal.
!expr = True if the expr evaluates to false.
expr1 –a expr2 = True if both expr1 and expr2 are true.
expr1 –o expr2 = True is either expr1 or expr2 is true.
-lt ( é menor que? )
-gt ( é maior que? )
-le ( é menor ou igual a? )
-ge ( é maior ou igual a? )
-eq ( é igual a? )
-ne ( é diferente de? )
= ( é igual a? )
!= ( é diferente de? )
-n ( existe? )
-z ( é nula? )
! ( not )
-a ( and )
-o ( or )
Adição, subtração, mutiplicação, divisão, exponenciação etc (bc e dc)
# echo 9+2 | bc
# echo 9-2 | bc
# echo 9*8*7*6 | bc
# echo 9*8*7*6/2 | bc
# echo 9^2 | bc
# echo 8/2+2 | bc
# echo 8/'(2+2)' | bc
# expr 1 + 2
# expr 5 \* 2
# echo $((1+1))
# echo $((6/4))
# b=$((1+1))
O comando ECHO é muito utilizado em shell scripts
# echo $$ (mostra o process ID do shell corrente (ver: ps ax | grep –i bash) ou dentro de shell script mostra o process ID usado para executá-lo (na verdade é o número do subshell usado para roda o shell script))
# echo $0 (mostra qual é o shell corrente. Ex: bash)
# echo $n (onde “n” deve ser substituído por 1, 2, 3, ..., mostrando os parâmetros que foram passados. Ex: echo$1 mostra o primeiro parâmetro passado, echo$2 mostra o segundo parâmetro e assim sucessivamente)
# echo $ ()
# echo $? (mostra o status da saída (exit status) que é “0”. O valor normal de saída de um script shell é “0”. Para verificar se um script obteve sucesso, basta verificar o status de saída)
# echo $# (mostra o total de parâmetros passados)
# echo $! (mostra o process ID do último comando executado em background)
# echo $- ()
# echo $* (mostra todos os parâmetros passados)
# echo $@ (idem)
Referências Bibliográgicas
MOTA FILHO, J. E. Descobrindo o linux: entenda o sistema operacional GNU/Linux. 2. ed. São Paulo: Novatec, 2007.