Altro [Bash] Semplice email sorter

peste666

Utente Silver
12 Gennaio 2016
66
5
44
61
Ultima modifica:
Buonasera, viste l'esigenze di un utente sul gruppo Telegram che chiedeva uno script che gli dividesse un plaintext di tante email miste in tanti file testuali, spezzandola e creandone una per mail, ho scritto un semplice script in bash. Non sono un esperto, anzi sono ben accetti consigli. Per ora, lo script, fa il lavoro suo.

Ne ho create due versioni:
-Una che accetta il formato [email protected] e restituisce in una cartella chiamata emails tanti file di testo uno per provider spezzando la lista in piu liste.
-Uno che accetta anche il formato [email protected] : Password facendo la stessa cosa, ma mantenendo nell'output anche la password.

Usage:

Codice:
chmod +x mailonly.sh mailpassword.sh
./mailpassword.sh nomefile
./mailonly.sh nomefile

MAIL SORTER

Bash:
#!/bin/bash
#mail sorter v 0.1 _ peste666
#ATTENZIONE! DARE A QUESTO SCRIPT UN FILE FORMATO MAIL:PASSWORD GENERERÀ JUNK NELLA CARTELLA DI DESTINAZIONE. USARE L'ALTRO SCRIPT
#mail format version

#check che sia effettivamente stato inserito un nome
if [[ $# -eq 0 ]] ; then
    echo "Non hai inserito nessun argomento. Usage: ./mailpassword.sh nomefile"
    echo "www.inforge.net/forum/"
    exit 0
fi

#prendo il nome del file e salvo la variabile
plaintext=$1

#check se il file esiste
if [ ! -f $plaintext ]; then
    echo "File non trovato!"
    exit
fi

#Con la seguente riga vengono ordinate e in seguito tagliate tutte le mail creando una lista in un file chiamata listasolomail
sort -t '@' -k2 $plaintext | awk -F '@' '{print $2}' | uniq > listasolomail

#creiamo una cartella per pulizia
mkdir emails && cd emails

#creo un nuovo script grepfile.sh che contiene il comando per greppare la lista di mail  in ogni riga.
awk -v var="$plaintext" '{print "grep " $1 " ../"var" >> " $1}' ../listasolomail > grepfile.sh

#rendiamo il nuovo script eseguibile e lo eseguo
chmod +x grepfile.sh

#eseguo lo script generato
./grepfile.sh 2> /dev/null

#rimuovo i file creati in precedenza. In caso sia anche necessaria la lista delle email, commentate l'ultima riga.
rm grepfile.sh
rm ../listasolomail

Bash:
#!/bin/bash
#mail sorter v 0.2 by matt
#ATTENZIONE! DARE A QUESTO SCRIPT UN FILE FORMATO MAIL:PASSWORD GENERERÀ JUNK NELLA CARTELLA DI DESTINAZIONE. USARE L'ALTRO SCRIPT
#mail format version

#check che sia effettivamente stato inserito un nome
if [[ $# -eq 0 ]] ; then
    echo "Non hai inserito nessun argomento. Usage: ./mailpassword.sh nomefile"
    echo "www.inforge.net/forum/"
    exit 0
fi

#chiedo il nome del file e salvo la variabile
plaintext=$1

if [ ! -f $plaintext ]; then
    echo "File non trovato!"
    exit
fi

#Con la seguente riga vengono ordinate e in seguito tagliate tutte le mail creando una lista in un file
#chiamata listasolomail
sort -t '@' -k2 $plaintext | awk -F '@' '{print $2}' | uniq > listasolomail

#creiamo una cartella per pulizia
cartella=emails/

if [ -d "$cartella" ]; then
    echo "la cartella emails già esiste"
fi

if [ ! -d "$cartella" ]; then
    echo "la cartella emails non esiste, la creo..."
    mkdir emails
fi


cd emails

#creo un nuovo script grepfile.sh che contiene il comando per greppare la lista di mail  in ogni riga.
awk -v var="$plaintext" '{print "grep " $1 " ../"var" >> " $1}' ../listasolomail > grepfile.sh

#rendiamo il nuovo script eseguibile e lo eseguo
chmod +x grepfile.sh
chmod +r ../listasolomail

#commentare questa riga in caso il lo script non si voglia eseguire subito. commentare anche il comando che elimina questo file
#quattro righe più avanti
./grepfile.sh 2> /dev/null

#rimuovo i file creati in precedenza
#in caso sia anche necessaria la lista delle email, commentate solo l'ultima riga.
rm grepfile.sh
rm ../listasolomail
Versione funzionante, la 0.1 presentava problemi se si provava ad appendere nuovi plaintext in una cartella email già esistente. Aggiunti check per la cartella.

MAIL E PASSWORD SORTER

Bash:
!/bin/bash
#mail sorter v 0.1 _ peste666
#mail:password format version


#check che sia effettivamente stato inserito un nome
if [[ $# -eq 0 ]] ; then
    echo "Non hai inserito nessun argomento. Usage: ./mailpassword.sh nomefile"
    echo "www.inforge.net/forum/"
    exit 0
fi

#prendo il nome del file e salvo la variabile
plaintext=$1

#check se il file esiste

if [ ! -f $plaintext ]; then
    echo "File non trovato!"
    exit 0
fi

#Con la seguente riga vengono ordinate e in seguito tagliate tutte le mail creando una lista in un file chiamata listasolomail
sort -t '@' -k2 $plaintext | awk -F ':' '{print $1}' | awk -F '@' '{print $2}' | uniq > listasolomail

#creiamo una cartella per pulizia
mkdir emails && cd emails

#creo un nuovo script grepfile.sh che contiene il comando per greppare la lista di mail  in ogni riga.
awk -v var="$plaintext" '{print "grep " $1 " ../"var" >> " $1}' ../listasolomail > grepfile.sh

#rendiamo il nuovo script eseguibile e lo eseguo
chmod +x grepfile.sh

#eseguo lo script generato
./grepfile.sh 2> /dev/null

#rimuovo i file creati in precedenza. In caso sia anche necessaria la lista delle email, commentate l'ultima riga.
rm grepfile.sh
rm ../listasolomail

Bash:
#!/bin/bash
#mail sorter v 0.2 by matt
#mail:password format version

if [[ $# -eq 0 ]] ; then
    echo "Non hai inserito nessun argomento. Usage: ./mailpassword.sh nomefile"
    echo "www.inforge.net/forum/"
    exit 0
fi

#chiedo il nome del file e salvo la variabile
plaintext=$1

if [ ! -f $plaintext ]; then
    echo "File non trovato!"
    exit 0
fi

#Con la seguente riga vengono ordinate e in seguito tagliate tutte le mail creando una lista in un file
#chiamata listasolomail
sort -t '@' -k2 $plaintext | awk -F ':' '{print $1}' | awk -F '@' '{print $2}' | uniq > listasolomail

#creiamo una cartella per pulizia
cartella=emails/

if [ -d "$cartella" ]; then
    echo "la cartella emails già esiste"
fi

if [ ! -d "$cartella" ]; then
    echo "la cartella emails non esiste, la creo..."
    mkdir emails
fi


cd emails

#creo un nuovo script grepfile.sh che contiene il comando per greppare la lista di mail  in ogni riga.
awk -v var="$plaintext" '{print "grep " $1 " ../"var" >> " $1}' ../listasolomail > grepfile.sh

#rendiamo il nuovo script eseguibile e lo eseguo
chmod +x grepfile.sh
chmod +r ../listasolomail

#commentare questa riga in caso il lo script non si voglia eseguire subito. commentare anche il comando che elimina questo file
#quattro righe più avanti
./grepfile.sh 2> /dev/null

#rimuovo i file creati in precedenza
#in caso sia anche necessaria la lista delle email, commentate solo l'ultima riga.
rm grepfile.sh
rm ../listasolomail
Versione funzionante, la 0.1 presentava problemi se si provava ad appendere nuovi plaintext in una cartella email già esistente. Aggiunti check per la cartella.

---------

Ben accetti consigili! lo script sembra abbastanza veloce nella sua esecuzione. i tempi di esecuzione dipendono dal file che gli date in pasto. Cheers!

peste666
 
Quello che vuoi fare tu:

MAIL SORTER

Bash:
#!/bin/bash
#mail sorter v 0.1 _ peste666
#ATTENZIONE! DARE A QUESTO SCRIPT UN FILE FORMATO MAIL:PASSWORD GENERERÀ JUNK NELLA CARTELLA DI DESTINAZIONE. USARE L'ALTRO SCRIPT
#mail format version

#check che sia effettivamente stato inserito un nome
if [[ $# -eq 0 ]] ; then
echo "Non hai inserito nessun argomento. Usage: ./mailpassword.sh nomefile"
echo "www.inforge.net/forum/"
exit 0
fi

#prendo il nome del file e salvo la variabile
plaintext=$1

#check se il file esiste
if [ ! -f $plaintext ]; then
echo "File non trovato!"
exit
fi

#Con la seguente riga vengono ordinate e in seguito tagliate tutte le mail creando una lista in un file chiamata listasolomail
sort -t '@' -k2 $plaintext | awk -F '@' '{print $2}' | uniq > listasolomail

#creiamo una cartella per pulizia
mkdir emails && cd emails

#creo un nuovo script grepfile.sh che contiene il comando per greppare la lista di mail in ogni riga.
awk -v var="$plaintext" '{print "grep " $1 " ../"var" >> " $1}' ../listasolomail > grepfile.sh

#rendiamo il nuovo script eseguibile e lo eseguo
chmod +x grepfile.sh

#eseguo lo script generato
./grepfile.sh 2> /dev/null

#rimuovo i file creati in precedenza. In caso sia anche necessaria la lista delle email, commentate l'ultima riga.
rm grepfile.sh
rm ../listasolomail

si può fare in un comando più semplice e schietto: grep -i -o '[A-Z0-9._%+-]\+@[A-Z0-9.-]\+\.[A-Z]\{2,4\}' emails.txt > parsedEmails.txt come deduco tutto il resto.
 
  • Mi piace
Reazioni: peste666
Quello che vuoi fare tu:



si può fare in un comando più semplice e schietto: grep -i -o '[A-Z0-9._%+-]\+@[A-Z0-9.-]\+\.[A-Z]\{2,4\}' emails.txt > parsedEmails.txt come deduco tutto il resto.
Ti ringrazio per il consiglio. mi sto ancora studiando le espressioni regolari e non mi sento abbastanza ferrato da poterle utilizzare, ho cercato di usare tutto quello che conosco per ora e di creare un workaround. Dopo lo provo e appena posso lo implemento.

Io volevo ottenere da un file unico, una lista di email miste, tanti file uno per dominio in una cartella e di fatto lo script lo fa.

Mi spiego:

listadiemail.txt=
[email protected]
[email protected]
[email protected]

Con lo script

./mailonly.sh listadiemail.txt

ottengo in una cartella emails vari file di testo, uno per dominio quindi:

emails/
gmail.com
yahoo.com

I quali a loro volta contengono le email presenti nella prima lista ma divise per dominio ed in ordine alfabetico:

cat gmail.com:
[email protected]

cat yahoo.com:
[email protected]
[email protected]

Peste
 
Ultima modifica:
Ecco la mia proposta
Bash:
while read -r line; do
  printf "%s\n" "${line}" >> "$(printf "${line}" | grep -Po '(?<=@).+(?=\.)')"
done < listadiemail.txt
Funziona con tutte le shell POSIX ;)

EDIT: il comportamento di echo non è definito nello standard quindi è buona norma usare printf
 
  • Mi piace
Reazioni: peste666
Ecco la mia proposta
Bash:
while read -r line; do
  printf "%s\n" "${line}" >> "$(printf "${line}" | grep -Po '(?<=@).+(?=\.)')"
done < listadiemail.txt
Funziona con tutte le shell POSIX ;)

EDIT: il comportamento di echo non è definito nello standard quindi è buona norma usare printf

Molto bello! Alla fine il mio script si poteva riassumere in 5 righe, togliendo i vari ghirigori e i check:

Bash:
plaintext=$1
sort -t '@' -k2 $plaintext | awk -F ':' '{print $1}' | awk -F '@' '{print $2}' | uniq > listasolomail
awk -v var="$plaintext" '{print "grep " $1 var" >> " $1}' listasolomail > grepfile.sh
chmod +x grepfile.sh
./grepfile.sh

ma il tuo è senza dubbio più corretto. Potresti spezzare i vari passi? Avevo pensato anche io a sviluppare qualcosa con while read line, ma non avevo idea di come proseguire! piuttosto che sbatterci la testa, ho costruito un workaround che funziona nel mio caso specifico!
 
Il ciclo prende in input il file listadiemail.txt con l'operatore di redizionamento <
Ogni riga viene quindi letta da read ed immagazzinata in $line, escludendo i caratteri di escape con -r (questa è solo una mia abitudine :p)

Quindi ad ogni ciclo si calcola il dominio della mail con "$(printf "${line}" | grep -Po '(?<=@).+(?=\.)')", che viene successivamente usato come nome del file su cui scrivere (o meglio, appendere >>) ogni riga letta.

Spiegazione passo per passo "dall'interno all'esterno":
  1. printf "${line}" stampa la riga corrente in stdout senza newline
  2. | redireziona l'stdout di printf all'stdin di grep, ma già lo sai :)
  3. grep -P interpreta l'espressione regolare in sile perl. La sintassi è la seguente: '(?<=ultimocaratteredaescludere)<regex>(?=primocaratteredaescludere)'. Quindi '(?<=@).+(?=\.)' corrisponde alla stringa contenuta tra @ e . (punto). In pratica estrae "gmail" da "[email protected]"
  4. Manda il risultato (nel caso precedente, "google") in stdout
  5. Come noti però l'espressione è contenuta in $(), che è l'operatore di command substitution. Significa che $(...) verrà sostituito con l'output prodotto dai comandi che ci metti dentro. Nel nostro caso viene sostituito con il nome del dominio.
  6. Scrive (appende) ogni riga letta ed immagazzinata in $line su un nuovo file avente il nome del dominio determinato da $(...)
 
  • Mi piace
Reazioni: peste666
Ecco la mia proposta
Bash:
while read -r line; do
  printf "%s\n" "${line}" >> "$(printf "${line}" | grep -Po '(?<=@).+(?=\.)')"
done < listadiemail.txt
Funziona con tutte le shell POSIX ;)

EDIT: il comportamento di echo non è definito nello standard quindi è buona norma usare printf
Non è necessario intricarsi la vita con cicli e roba varia, sed permette già di fare quello che desidera in una riga di comando (come ho fatto vedere precedentemente, però raggruppando l'espressione regolare). sed -r 's/([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\.[A-Za-z]{2,4})/echo "\0" >> \2.txt/e' listadiemail.txt è tutto quello che gli serve.

Codice:
~ $ cat listadiemail.txt
[email protected]
[email protected]
[email protected]
~ $ sed -r 's/([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\.[A-Za-z]{2,4})/echo "\0" >> \2.txt/e' listadiemail.txt
~ $ ls | grep txt
... altri file di testo ...
gmail.com.txt
yahoo.com.txt

ho utilizzato la stessa espressione regolare di prima, il secondo gruppo contrassegna il dominio dell'email.
Codice:
~ $ cat gmail.com.txt
[email protected]
~ $ cat yahoo.com.txt
[email protected]
[email protected]
 
Non c'è neanche bisogno di complicarsi la vita con sed ;)
sed -r 's/(.+)@(.+)/echo "\0" >> \2.txt/e' listadiemail.txt

EDIT: magari con >/dev/null alla fine per evitare le righe inutili aha
 
Non c'è neanche bisogno di complicarsi la vita con sed ;)
sed -r 's/(.+)@(.+)/echo "\0" >> \2.txt/e' listadiemail.txt
Infatti non vuol dire che una espressione regolare più piccola sia meglio... insomma, così stai parsando pure email non valide:
non si possono avere numeri dopo il punto del dominio dell'email, e sicuramente potrebbe portare pure ad altri output indesiderabili. Una "espressione regolare" troppo sommaria non è mai buona, quindi ripropongo:
sed -r 's/([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\.[A-Za-z]{2,4})/echo "\0" >> \2.txt/e' listadiemail.txt
 
Bhe, volendo essere pignoli il top-level domain può essere compreso tra gli 1 e i 63 caratteri quindi la tua regex starebbe missando molte email valide :confused:

Questo è vero, anche se la tua precisazione è abbastanza pedantesca... In quell'eventuale e rara eccezione basterebbe sostituire il quantificatore {2,4} con {2,}, ma secondo me andrebbe già bene così.
L'importante è non utilizzare l'altra espressione regolare che hai consigliato, altrimenti ho questa roba convalidata come delle email:
Codice:
google@google
.googogogogogo.goooogoogle@google.gooogle.goooooooogle.gooooooooooooooooooooooooooooooooo
@@@
9@9@9@##
1@1
~@~
 
Ultima modifica:
Questo è vero, anche se la tua precisazione è abbastanza pedantesca... In quell'eventuale e rara eccezione basterebbe sostituire il quantificatore {2,4} con {2,}, ma secondo me andrebbe già bene così.
L'importante è non utilizzare l'altra espressione regolare che hai consigliato, altrimenti ho questa roba convalidata come delle email:
Codice:
google@google
.googogogogogo.goooogoogle@google.gooogle.goooooooogle.gooooooooooooooooooooooooooooooooo
@@@
9@9@9@##
1@1
~@~
okay ahah mi arrendo