Dúvida com AWK [RESOLVIDO]

1. Dúvida com AWK [RESOLVIDO]

Matheus Britto
Aimagem

(usa Slackware)

Enviado em 21/01/2013 - 03:42h

Pessoal,

Recentemente, me deparei com um problema aparentemente simples de ser resolvido, mas que até o momento não consegui - e que já está me deixando maluco.
Tenho um arquivo com os nomes e mails dos funcionários da empresa, apresentados da seguinte forma:



names.dat
nome do funcionário:mail@servidor
nome do funcionário:mail@servidor
nome do funcionário:mail@servidor
nome do funcionário:mail@servidor
nome do funcionário:mail@servidor
.
.
.

Com o commando awk "BEGIN{FS=":"}{print $1}' < names.dat pro exemplo, aparecem todos os nomes. awk "BEGIN{FS=":"}{print $2}' < names.dat aparecem todos os mails.
O que preciso é poder acessar, tipo, o nome da linha "N" ou o mail da linha "Y". Seria como poder fazer um awk "BEGIN{FS=":"}{print $1[linha 1]}' < names.dat para me mostrar apenas o nome correspondente.

Tem como fazer isso com o awk ou de outra forma no bash?

Abraços,

Matheus


  


2. Re: Dúvida com AWK [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 21/01/2013 - 07:52h

Poder... pode sim. leia o artigo do link abaixo e você conseguirá fazer o que está querendo.

http://www.vivaolinux.com.br/artigo/AWK-Introducao/


3. Re: Dúvida com AWK [RESOLVIDO]

Matheus Britto
Aimagem

(usa Slackware)

Enviado em 21/01/2013 - 21:32h

eabreu escreveu:

Poder... pode sim. leia o artigo do link abaixo e você conseguirá fazer o que está querendo.

http://www.vivaolinux.com.br/artigo/AWK-Introducao/


eabreu,

Muito boa e interessante sua indicação, mas ainda não consegui fazer o que preciso. §:-/
Se souber de mais alguma fonte de informação que possa me ajudar, fico grato.

Abraços.


4. Re: Dúvida com AWK [RESOLVIDO]

cr0n
_di0

(usa FreeBSD)

Enviado em 21/01/2013 - 22:12h

awk disponibiliza de algumas variáveis construídas, como NF (Number of Fields) e NR (Number of records), algo bem singelo como:

awk 'BEGIN{FS=":"}{if (NR == 2) print $1}' < foo.dat

Fará com que a segunda linha seja extraída, uma vez NR contendo o número de registros de entrada. Quando se trata de extração linhas, é de coerência utilizar-se do SED ou Perl.


5. Re: Dúvida com AWK [RESOLVIDO]

Matheus Britto
Aimagem

(usa Slackware)

Enviado em 22/01/2013 - 06:48h

_di0 escreveu:
awk 'BEGIN{FS=":"}{if (NR == 2) print $1}' < foo.dat
Fará com que a segunda linha seja extraída, uma vez NR contendo o número de registros de entrada. Quando se trata de extração linhas, é de coerência utilizar-se do SED ou Perl.


_di0,

Era mais ou menos isso que estava procurando fazer. O problema é que como o arquivo tem muitas linhas - 30 se não me engano - contendo os nomes e emails de cada funcionário, repetir esse comando várias vezes se torna praticamente inviável. Imagine quando começar a fazer a correspondência dos nomes com os emails. O dobro de comandos. Será que não existe uma forma mais "automatizada" de se fazer isso?

Além do que, testar as variáveis também não seria nada prático, pois como o comando é muito extenso, dá erro.

Sobre o SED, reconheço que não sei nada sobre ele, mas se for uma alternativa viável, estou aberto à sugestões.

De qualquer modo, agradeço pela ajuda.

Abraços,

Matheus.


6. Re: Dúvida com AWK [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 22/01/2013 - 09:07h

Trinta linhas não chega a ser muito para a maioria das coisas a que estamos acostumados no dia-a-dia. Qual o seu contexto? Qual o resultado que você deseja?

Já houve uma discussão parecida com a que você suscitou (ver http://www.vivaolinux.com.br/topico/Shell-Script/Ler-Determinada-linha-em-um-arquivo-txt).

Quando eu estou preocupado com eficiência do programa, geralmente não uso shell. Quando estou preocupado com eficiência no acesso a dados que dependam de busca, geralmente não uso arquivos texto.

Estou com isso dizendo que você deve usar C/Perl/Python, com dados em formato DBM/Berkeley-DB/SQLite/DBMS? Talvez sim, talvez não, mas depende de você nos dar melhores informações.


7. Re: Dúvida com AWK [RESOLVIDO]

Matheus Britto
Aimagem

(usa Slackware)

Enviado em 22/01/2013 - 15:57h

Paulo,

Como não sou programador - digo, não vivo disso - aprender novas linguagens aos 44 do segundo tempo seria muito trabalhoso para pouco uso prático. Mas claro que, conhecimento nunca é demais e quem sabe não possa fazer isso aos poucos?
Sobre minha dúvida, ela é mais para solucionar - de forma "caseira" - uma questão de automação que temos aqui na agência para envio de relatórios para nossos funcionários. Podemos fazer isso manualmente? Claro que podemos. Seria mais prático ser automatizado? Claro que seria. Mas isso não seria um motivo para se investir muito esforço ou até mesmo dinheiro nisso. Seria apenas pela praticidade mesmo.

Sobre a questão…

O script que fiz para gerar os relatórios individuais está funcionando perfeitamente bem, gerando tanto o da data atual quanto de datas anteriores se desejarmos. A questão é que queria verificar, após gerar os relatórios, para qual endereço de email o arquivo deve ser enviado, baseado na lista que criei. Correspondência entre nome do arquivo = nome do funcionário.

Exemplo:

script # ele criou os seguintes arquivos
janedoe.log
georgebush.log

names.dat # nomes dos funcionários com seus respectivos emails.
johndoe:johndoe@mail.com
janedoe:jane@mail.com
georgebush:bush@mail.com

Diante disso, verificar para qual email o relatório deve ser enviado.
Note que para o nome da primeira linha, não houve relatório, então ele deve continuar verificando a correspondência.

Como as vezes temos funcionários temporários, seria interessante poder fazer isso de forma automática, mudando apenas o conteúdo do arquivo names.dat e não o script em si.
Pensando nisso, me de deparei com a questão de como saber quantas linhas o arquivo .dat teria para poder testar todos os nomes até o final do arquivo, mas me lembrei do wc -l para contar as linhas.

Qualquer outra informação que posa ajudar, fico grato.

Abraços,

Matheus.


8. Re: Dúvida com AWK [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 22/01/2013 - 16:37h

Mas precisa saber a priori? Não pode fazer um loop do tipo while read nome endereco; do ... done, lendo cada linha para pegar tanto o nome quanto o endereço, e depois mandar a mensagem?


9. Re: Dúvida com AWK [RESOLVIDO]

Matheus Britto
Aimagem

(usa Slackware)

Enviado em 23/01/2013 - 00:28h

Paulo,

Claro que pode. Na verdade, ele primeiro gera os relatórios individuais, para só então, fazer a correlação entre nome do arquivo com o nome dentro da lista .dat.
E depois de quebrar um pouco a cabeça aqui e, com as dicas e ajuda de vocês, cheguei ao script abaixo.


#!/bin/bash

list=$(ls -1)

for file in $list
do

line=1
total=$(cat names.dat | wc -l)

while [ $line -le $total ]
do

name=$(awk 'BEGIN{FS=":"}{if (NR == '$line') print $1}' names.dat)
mail=$(awk 'BEGIN{FS=":"}{if (NR == '$line') print $2}' names.dat)

if [ -e $file ]
then
if [ "$file" == "$name" ]
then
`mail -s "Relatório do dia $(date +%Y%m%d)" $mail < $file`
fi
fi
line=$((line+1))
done
done


Testei aqui e, em todas as vezes, ele encontrou o arquivo correspondente e enviou para o mail correto. Mas se tiverem mais alguma indicação de como melhorá-lo ou se encontrarem alguma falha que não esteja vendo no momento, sintam-se à vontade para comentar.

Mais uma vez, obrigado pela ajuda pessoal.

Abraços


10. Re: Dúvida com AWK [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 23/01/2013 - 20:19h

Não entendi a razão de você rter posto o e-nvio de email entre sinais de de acento grave. Usar `comando` tem o mesmo sentido de $(comando): fazer com que o shell pegue a saída de comando e interprete como uma string que é parte de outro comando que ele vai executar. Assim sendo, algo como echo `echo ls` vai imprimir o texto "ls", e `echo ls` será equivalente simplesmente ao comando ls.

Mas que tal deixar o script como um todo mais eficiente, usando algumas dicas trocadas com você aqui no fórum nas últimas duas semanas?

#!/bin/bash

# Define o valor da data apenas uma vez, fora do loop, ja que ela nao
# deve mudar ao longo da execucao do script.
today=`date "+%Y/%m/%d"`

# O shell também tem variável que define separador de campos, que pode
# ser usado junto com o comando interno read.
IFS=":"

# Obtem descritor apontando para o arquivo com nomes e enderecos.
exec 3< names.dat

# Loop varrendo cada par de nome e endereco.
while read name address <&3; do
# Ve se existe arquivo com mesmo nome do destinatario
[[ -e $name ]] && mail -s "Relatorio do dia $today" $address < $name
done

# Libera o descritor 3
exec 3<&-



11. Re: Dúvida com AWK [RESOLVIDO]

Matheus Britto
Aimagem

(usa Slackware)

Enviado em 24/01/2013 - 06:26h

Paulo,

O mail não estava sendo executado corretamente - na verdade de forma alguma - sem ser dessa forma. Não sei o que aconteceu, mas da mesma forma que parou, voltou a funcionar sozinho.

Sobre o script, eu já imaginava que da forma que havia feito poderia ser melhorada. Afinal, fui pelo caminho mais longo e complicado para chegar onde queria.
E se me permite dizer, sua solução chega a ser - com o perdão da palavra - ridiculamente simples e obvia depois de visualizada.

Entretanto, com o script que fiz para gerar os relatórios - que pode ser da data atual ou de uma data anterior - fiquei com dúvidas sobre como proceder para o caso de um data anterior.
Poderia declarar tudo antes do if e utilizar apenas a parte do envio da mensagem para cada teste? Seria melhor utilizar [[ comando ]] ou if…then…elif…fi? Teria como simplificar esse script também ou melhor deixá-lo como está?


#!/bin/bash

# Cada linha dentro do arquivo do relatório sempre é "lugar_fotógrafo_nomedaimagem.jpg"
# e no caso, preciso saber quem fez a imagem para poder gerar o relatório com o nome dele,
# por isso uso o grep com a variável $nome.

today=`date "+%Y%m%d"` # data atual.
logold="report_$1.log" # arquivo de uma data digitada, podendo ser a atual ou mais antiga.
lognew="report_$today.log" # arquivo da data atual.

logdir="/private/var/log"

if [ ! -n "$1" ] && [ -e $logdir/$lognew ]
then
exec 3< <(cat $logdir/$lognew | sort)
while read -a line <&3
do
name="${line%_*_*}"
name="${name##*_}"
echo $line | grep $name >> $logdir/"$name"_"$today".log
done
exec 3<&-
elif [ -e $logdir/$logold ]
then
exec 3< <(cat $logdir/$logold | sort)
while read -a line <&3
do
name="${line%_*_*}"
name="${name##*_}"
echo $line | grep $name >> $logdir/"$name"_"$1".log
done
exec 3<&-
fi


Mais uma vez, te agradeço imensamente à ajuda.

Abraços,


12. Re: Dúvida com AWK [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 24/01/2013 - 13:53h

Não entendi direito o que você quis fazer dentro dos loops com while. Não sei se você confundiu os nomes das variáveis na hora de transcrever, mas veja que a segunda atribuição de name é inútil. E aquele grep também é esquisito, pois se você obteve name a partir de line, é óbvio que o a execução de "echo $line | grep $name" sempre será equivalente a simplesmente "echo $line".

Eu evitaria a duplicação de código e o uso temerário de variáveis que podem não estar definidas.


#!/bin/bash

# Cada linha dentro do arquivo do relatório sempre é "lugar_fotógrafo_nomedaimagem.jpg"
# e no caso, preciso saber quem fez a imagem para poder gerar o relatório com o nome dele,
# por isso uso o grep com a variável $nome.

logdir="/private/var/log"

if (( $# == 1 )); then
date=$1
elif (( $# == 0 )); then
date=`date +%Y%m%d`
else
echo "Modo de usar: $0 [data]" >&2
exit 1
fi
logfile="$logdir/report_$date.log"

IFS="_"
exec 3< <(sort "$logfile")
while read place photogapher image_name <&3
do
echo $line >> "$logdir/${photographer}_${date}.log" # Supondo que entendi o que você quis fazer...
done
exec 3<&-







Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts