shell-script-pt
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [shell-script] especie de "if-then-else" com sed


From: Julio C. Neves
Subject: Re: [shell-script] especie de "if-then-else" com sed
Date: Wed, 1 Oct 2014 18:34:47 -0300

Fala Marcelo,
na 10ª edição do meu livro (que está prestes a chegar no mercado e está muito boa), eu resolvi mergulhar fundo no sed (40 páginas A4) e engrossar o apêndice do awk. Escrevi inclusive sobre uma forma de fazer desvios dentro do sed, que pode ser a saída para o seu problema. Vou colar aqui em baixo a sub seção do livro onde falo sobre estes desvios.

Depois comente na lista se vc conseguiu resolver o problema com isso ou não e se o texto está elucidativo (mas é necessário um bom conhecimento de sed para entender).

Uma forma de vc fazer é ir lendo para o pattern space com o cmd N, pesquisar se é a última linha do bloce e fazer um branch conditional para imprimir o que está bufferizado.

Outra forma de fazer é enfiar uma linha vazia após a última linha de cada bloco e proceder exatamente como fiz no exemplo que dei no desvio incondicional. Por exemplo vou colocar uma linha vazia após cada linha terminada em 3. A minha massa de teste é gerada pelo cmd:

$ echo {1..5}{1..3} | tr ' ' '\n'

e para colocar uma linha vazia, basta fazer:

$ echo {1..5}{1..3} | tr ' ' '\n' | sed '/3$/a\
> '

OBS: o sinal de maior (>) foi o prompt secundário que o bash botou qdo fiz a quebra de linha.

Alterando o fluxo do programa

Lá no início deste capítulo, dissemos que o sed, por ser uma linguagem de programação completa, possui comandos para controle e desvio de fluxo. Vamos ver como fazer isso.

Muitas vezes somos obrigados a criar um desvio (em inglês branch) que ocorrerá dependendo de uma condição e outras vezes precisamos de um desvio incondicional, em que o fluxo do programa é sempre desviado.

O primeiro que citamos, o condicional, é chamado pelo comando t e desviará para um ponto do sed caso a última substituição (s/.../.../) tenha sido bem executada;

O segundo, o incondicional, é chamado pelo comando b e sempre desviará para um outro ponto do script.

Especificando rótulos (labels)

Para mudar o fluxo de execução do sed, você precisa especificar o endereço para o qual haverá o desvio e rotular esse local. Caso este rótulo não tenha sido definido, o desvio se dará para o final do script. Para criar um rótulo, basta preceder com um dois pontos (:) o nome que você escolheu e colocá-lo no endereço para o qual você deseja que o programa vá.

...

:ROTULO

...

Testando condições

Veja esse exemplo, onde desejamos trocar todas as letras minúsculas que ocorram antes de um hífen (-) por um algarismo 0.

$ sed -r '{

> :volta

> s/^([^-]*)[a-z]/\10/

> t volta

> }' <<< abc9Aaa-a111a

0009A00-a111a

A primeira linha do script é o rótulo :volta, a segunda linha troca (s) a partir do início (^), tudo que não é hífen (([^⁻]*)) e tenha uma letra minúscula ([a-z]) após. Isso será trocado pelo valor do retrovisor (\1) cujo texto foi gerado pelo grupo definido pelos parênteses, seguido por um zero. O comando t da terceira linha, diz para o fluxo voltar para o rótulo :volta caso a substituição tenha sido bem sucedida, pois isto é sinal que ainda pode haver mais letra(s) para ser(em) substituída(s). Como houve um retorno, o sed não será completado enquanto estiver achando letras e por isso não lerá outro registro, isto é, formamos um loop para cada linha lida que tenha letra(s) antes do um hífen (-). Caso a linha não tenha hífen (-), todas as letras serão trocadas por zeros.

Uma coisa interessante é que nesse caso, a execução será feita de traz para a frente e, para você ver todos os passos do loop sobre a mesma linha, vamos inserir o comando P. Veja:

$ sed -r '{

> :volta

> P

> s/^([^-]*)[a-z]/\10/

> t volta

> }' <<< abc9Aaa-a111a

abc9Aaa-a111a

abc9Aa0-a111a

abc9A00-a111a

ab09A00-a111a

a009A00-a111a

0009A00-a111a

0009A00-a111a

Desvio incondicional

No exemplo a seguir, tirado de http://www.grymoire.com/Unix/Sed.html#uh-58 (Valew!), veremos alguns desvios incondicionais, que acarretam mudanças no fluxo de execução do script.

Ele serve listar todos os parágrafos que contenham uma determinada cadeia que estão em um arquivo especificado. Para isso partimos dos seguintes pressupostos:

Para facilitar a explicação, cada linha do código será numerada (cat -n). Veja:

$ cat -n testa_branch.sh

1 #!/bin/sh

2 sed -n "

3 # Se linha vazia, vá pesquisar cadeia

4 /^$/ b PesqCad

5 # Senão, acrescenta a linha ao hold buffer

6 H

7 # Fim de arquivo também é fim de parágrafo

8 $ b PesqCad

9 # Vai para o fim para saltar PesqCad

10 b

11 # Aqui que vamos procurar a cadeia no parágrafo

12 :PesqCad

13 # Manda todo o parágrafo para o pattern space

14 x

15 # Procura a cadeia, se achar imprime

16 /$1/ p

17 " $2

Linha

Para fazer...

4

/^$/ pesquisa linha vazia e quando a acha, vai para (b) PesqCad para pesquisar a cadeia no arquivo

6

Se não foi para PesqCad, acrescenta esta linha ao Hold Space (H) para ir montando o parágrafo nele

8

Caso encontre o fim ($), do arquivo, que também é fim de parágrafo, vai para (b) a rotina PesqCad

10

Como a seguir vem a rotina PesqCad, esse desvio (b) vai para o fim do sed (porque está sem rótulo)

12

Rótulo da rotina

14

Manda o conteúdo do Hold Space para o Pattern Space (x) para ali poder trabalhar este parágrafo

16

Pesquisa a cadeia passada como parâmetro (/$1/) e, caso exista, imprime todo o conteúdo do buffer

17

Arquivo





Abcs,
Julio
@juliobash
Próximos cursos de Shell
Cidade         Local Período
Rio de Janeiro EDX 10 a 14/11
São Paulo 4Linux 24 a 28/11
Dou treinamento de Shell em qualquer cidade.
Para mais detalhes, me mande um e-mail.


Em 1 de outubro de 2014 15:18, Marcelo F Andrade address@hidden [shell-script] <address@hidden> escreveu:
 

Olá, gente.

O título comunica mas não explica.

Estou tentando fazer um script para identificar o tipo de autenticação
das redes wifi de onde estou a partir da saída do iwlist scan.

De forma resumida, há duas linhas nessa saída que me dizem isso:
- se houver uma linha "Encryption key:off", a rede está aberta;
- caso contrário, se houver também uma linha "WPA Version 1", a
autenticação é WPA;
- caso contrário, a autenticação é WEP.

O que fiz até o momento foi

iwlist wlan0 scan | \
grep -Eo '(ESSID:".+"|Quality=[0-9]{,2}/[0-9]{2}|Encryption
key:(on|off)|WPA Version (1|2))' | \
...

Passo essa saída ainda por um sed para, ao final, converter o
resultado de colunas para linhas com awk.

A questão é que como a linha "WPA Version" pode ou não existir, isso
está quebrando meu script.

Eis que pensei em fazer uma lógica e tentar colocar um placeholder
para identificar o tipo de autenticação. Mas aí já não consegui
resolver sozinho e vim recorrer a vós. :-)

Agradeço por qualquer ajuda.

Atenciosamente.

--
MARCELO F ANDRADE | Belem, Amazonia, Brazil | http://about.me/mfandrade



reply via email to

[Prev in Thread] Current Thread [Next in Thread]