Programação Shell LinuxAqui temos um livro livre e completo sobre ShellOs sedentos do "saber livre" são muito benvindos. |
Comandos Shell Script |
![]() |
|
Home |
Artigos ![]() ![]() |
Comprar o livroChangelogs |
|
Papo de Botequim - Parte III- Garçon, traga dois chopes por favor que hoje eu vou ter que falar muito. Trabalhando com cadeiasPelo título acima não pense você que vou lhe ensinar a ser carcereiro! Estou me referindo a cadeia de caracteres! O Comando cut (que não é a central de trabalhadores)
Primeiro quero te mostrar, de forma eminentemente prática uma instrução simples de usar e muito útil: o comando O comando
|
Principais Opções do comando tr | |
---|---|
-d | Remove os caracteres de cadeia1 |
Opção | Significado |
-s | Comprime n ocorrências de cadeia1 em apenas uma |
tr
Primeiro vou te dar um exemplo bem bobo:
Isto é, troquei todas as ocorrências da letra o
pela letra a
.
Suponha que em um determinado ponto do meu script eu peça ao operador para teclar s
ou n
(sim ou não), e guardo sua resposta na variável $Resp
. Ora o conteúdo de $Resp
pode estar com letra maiúscula ou minúscula, e desta forma eu teria que fazer diversos testes para saber se a resposta dada foi S
, s
, N
ou n
. Então o melhor é fazer:
e após este comando eu teria certeza que o conteúdo de $Resp
seria um s
ou um n
.
Se o meu arquivo ArqEnt
está todo escrito com letras maiúsculas e desejo passá-las para minúsculas eu faço:
Note que neste caso usei a notação A-Z
para não escrever ABCD...YZ
. Outro tipo de notação que pode ser usada são as escape sequences (prefiro escrever no bom e velho português, mas nesse caso como eu traduziria? Seqüências de escape? Meio sem sentido, né? Mas vá lá...) que também são reconhecidas por outros comandos e também na linguagem C, e cujo significado você verá a seguir:
Escape Sequences | ||
---|---|---|
\\ | Uma barra invertida | \0134 |
Seqüência | Significado | Octal |
\t | Tabulação | \011 |
\n | Nova linha |
\012 |
\v | Tabulação Vertical | \013 |
\f | Nova Página | \014 |
\r | Início da linha <^M> | \015 |
tr
Então deixa eu te contar um "causo": um aluno que estava danado comigo, resolveu complicar a minha vida e em um exercício prático valendo nota que passei para ser feito no computador, me entregou o script com todos os comandos separados por ponto-e-vírgula (lembra que eu disse que o ponto-e-vírgula servia para separar diversos comandos em uma mesma linha?).
Vou dar um exemplo simplificado e idiota de uma "tripa" assim:
Eu executava o programa e ele funcionava:
Mas nota de prova é coisa séria (e nota de dólar é mais ainda :)) então, para entender o que o aluno havia feito, o chamei e em sua frente executei o seguinte comando:
O cara ficou muito desapontado, porque em 2 ou 3 segundos eu desfiz a gozação que ele perdera horas para fazer.
Mas preste atenção! Se eu estivesse em uma máquina com Unix, eu teria feito:
tr
Agora veja a diferença entre os dois comandos date
: o que fiz hoje e outro que foi executado há duas semanas:
Para pegar a hora eu deveria fazer:
Mas duas semanas antes ocorreria o seguinte:
Mas observe porque:
Como você pode notar, existem 2 caracteres em branco antes do 5
(dia), o que estraga tudo porque o terceiro pedaço está vazio e o quarto é o dia (5
). Então o ideal seria comprimir os espaços em brancos sucessivos em somente um espaço para poder tratar as duas cadeias resultantes do comando date
da mesma forma, e isso se faz assim:
Como você pode ver não existem mais os dois espaços, então agora eu poderia cortar:
Olha só como o Shell já está quebrando o galho. Veja este arquivo que foi baixado de uma máquina com aquele sistema operacional que pega vírus:
E agora eu quero te dar duas dicas:
-v
do cat
mostra os caracteres de controle invisíveis, com a notação ^L
, onde ^
é a tecla control e L
é a respectiva letra. A opção -e
mostra o final da linha como um cifrão ($
).
\r
) e um line-feed (\n
). No Linux porém o final do registro tem somente o line-feed.
Vamos então limpar este arquivo.
Agora vamos ver o que aconteceu:
Bem a opção -d
do tr
remove o caractere especificado de todo o arquivo. Desta forma eu removi os caracteres indesejados salvando em um arquivo de trabalho e posteriormente renomeei-o para a sua designação original.
Obs: No Unix eu deveria fazer:
ftp
foi feito do modo binário (ou image
), isto é, sem a interpretação do texto. Se antes da transmissão do arquivo tivesse sido estipulada a opção ascii
do ftp
, isto não teria ocorrido.
- Olha, depois desta dica tô começando a gostar deste tal de Shell, mas ainda tem muita coisa que não consigo fazer.
- Pois é, ainda não te falei quase nada sobre programação em Shell, ainda tem muita coisa para aprender, mas com o que aprendeu, já dá para resolver muitos problemas, desde que você adquira o “modo Shell de pensar”. Você seria capaz de fazer um script para me dizer quais são as pessoas que estão “logadas” há mais de um dia no seu servidor?
- Claro que não! Para isso seria necessário eu conhecer os comandos condicionais que você ainda não me explicou como funcionam.
- Deixa eu tentar mudar um pouco a sua lógica e trazê-la para o “modo Shell de pensar”, mas antes é melhor tomarmos um chope... Ô Chico, traz mais dois...
- Agora que já molhei a palavra, vamos resolver o problema que te propus. Repare como funciona o comando who:
E veja também o date
:
Repare que o mês e o dia estão no mesmo formato em ambos os comandos.
date
para português.
Ora, se em algum registro do who
eu não encontrar a data de hoje, é sinal que o cara está "logado" há mais de um dia, já que ele não pode ter se "logado" amanhã... Então vamos guardar o pedaço que importa da data de hoje para procurá-la na saída do who
:
Eu usei a construção $(...)
, para priorizar a execução dos comandos antes de atribuir a sua saída à variável $Data
. Vamos ver se funcionou:
Beleza! Agora, o que temos que fazer é procurar no comando who
os registros que não possuem esta data.
- Ah! Eu acho que estou entendendo! Você falou em procurar e me ocorreu o comando grep
, estou certo?
- Certíssimo! Só que eu tenho que usar o grep
com aquela opção que ele só lista os registros nos quais ele não encontrou a cadeia. Você se lembra que opção é essa?
- Claro, é a opção -v
...
- Isso! Tá ficando bão! Então vamos ver:
- E se eu quisesse mais um pouco de perfumaria eu faria assim:
- Viu? Não foi necessário usar nenhum comando condicional, até porque o nosso mais usado comando condicional, o famoso if
, não testa condição, mas sim instruções, como veremos agora.
Veja as linhas de comando a seguir:
- O que é esse $?
faz aí? Começando por cifrão ($
) parece ser uma variável, certo?
- Sim é uma variável que contém o código de retorno da última instrução executada. Posso te garantir que se esta instrução foi bem sucedida, $? terá o valor zero, caso contrário seu valor será diferente de zero.
O que o nosso comando condicional if
faz é testar a variável $?
. Então vamos ver a sua sintaxe:
if cmd then cmd1 cmd2 cmdn else cmd3 cmd4 cmdm fi
ou seja: caso comando cmd
tenha sido executado com sucesso, os comandos do bloco do then
(cmd1
, cmd2
e cmdn
) serão executados, caso contrário, os comandos executados serão os do bloco opcional do else
(cmd3
, cmd4
e cmdm
), terminando com um fi
.
Vamos ver na prática como isso funciona usando um scriptizinho que serve para incluir usuários no /etc/passwd
:
Repare que o if
está testando direto o comando grep
e esta é a sua finalidade. Caso o if
seja bem sucedido, ou seja, o usuário (cujo nome está em $1
) foi encontrado em /etc/passwd
, os comandos do bloco do then
serão executados (neste exemplo é somente o echo
) e caso contrário, as instruções do bloco do else
é que serão executadas, quando um novo if
testa se o comando useradd
foi executado a contento, criando o registro do usuário em /etc/passwd
, ou não quando dará a mensagem de erro.
Vejamos sua execução, primeiramente passando um usuário já cadastrado:
Como já vimos diversas vezes, mas é sempre bom insistir no tema para que você já fique precavido, no exemplo dado surgiu uma linha indesejada, ela é a saída do comando grep
. Para evitar que isso aconteça, devemos desviar a saída desta instrução para /dev/null
, ficando assim:
Agora vamos testá-lo como usuário normal (não root):
Epa, aquele erro não era para acontecer! Para evitar que isso aconteça devemos mandar também a saída de erro (strerr, lembra?) do useradd
para /dev/null
, ficando na versão final assim:
Depois destas alterações e de fazer um su –
(me tornar root) vejamos o seu comportamento:
E novamente:
Lembra que eu falei que ao longo dos nossos papos e chopes os nossos programas iriam se aprimorando? Então vejamos agora como poderíamos melhorar o nosso programa para incluir músicas:
Como você viu, é uma pequena evolução da versão anterior, assim, antes de incluir um registro (que pela versão anterior poderia ser duplicado), testamos se o registro começava (^
) e terminava ($
) igual ao parâmetro passado ($1
). O uso do circunflexo (^
) no início da cadeia e cifrão ($
) no fim, são para testar se o parâmetro passado (o álbum e seus dados) são exatamente iguais a algum registro anteriormente cadastrado e não somente igual a um pedaço de algum dos registros.
Vamos executá-lo passando um álbum já cadastrado:
E agora um não cadastrado:
- Como você viu, o programa melhorou um pouquinho, mas ainda não está pronto. À medida que eu for te ensinando a programar em shell, nossa CDteca irá ficando cada vez melhor.
- Entendi tudo que você me explicou, mas ainda não sei como fazer um if
para testar condições, ou seja o uso normal do comando.
- Cara, para isso existe o comando test
, ele é que testa condições. O comando if
testa o comando test
. Mas isso está meio confuso e como já falei muito, estou precisando de uns chopes para molhar a palavra. Vamos parando por aqui e na próxima vez te explico direitinho o uso do test
e de diversas outras sintaxes do if
.
- Falou! Acho bom mesmo porque eu também já tô ficando zonzo e assim tenho tempo para praticar esse monte de coisas que você me falou hoje.
- Para fixar o que você aprendeu, tente fazer um scriptizinho para informar se um determinado usuário, que será passado como parâmetro esta logado (arghh!) ou não.
- Aê Chico, mais dois chopes por favor...
Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em Shell que mande um e-mail para a nossa gerencia de treinamento para informar-se.
Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para mim.
Valeu!