Scenario
Supponiamo che il vostro DBMS (MySQL) stia gestendo più database e che sia necessario effettuare delle query “a tappeto”, ovvero su tutte le tabelle relative a ciascuno di essi (cercando, ad esempio, un determinato record oppure un pattern specifico).
Eseguire tale operazione “a mano” può essere tedioso e soprattutto controproducente in termini di tempo. Come fare quindi? Semplice, realizzare uno scrip bash in grado di automatizzare tale attività.
Ecco il codice:
#!/bin/bash mysql -u utente -ppassword -e 'show databases' | grep -v Database | grep -v information_schema | grep -v mysql > databases while read line do command="mysql -u utente -ppassword -e 'use $line; show tables'" eval $command | grep -v "Tables_in_*" > tables_$line done < databases num_databases=`cat databases | wc -l` ls | grep "tables_*" > table num_tables=`cat table | wc -l` if [ $num_databases -eq $num_tables ];then for i in {1..19} do database=`cat databases | sed -n "$i p"` echo ".......tables for $database......." cat tables_"$database" | while read line do echo $line command="mysql -u utente -ppassword -e 'use $database; select * from $line LIMIT 1'" echo "....Executing $command...." >> result eval "$command" | tee -a result echo "....End executing $command ...." >> result done echo ".......end tables for $database......." done fi
Per prima cosa identifico tutti i database definiti su MySQL, escludendo quelli di default (mysql ed information_schema), formattando opportunamente l’output ( grep -v Database) e salvando i risultati all’interno del file databases:
mysql -u utente -ppassword -e 'show databases' | grep -v Database | grep -v information_schema | grep -v mysql > databases
Successivamente listo le tabelle presenti in ciascun database mediante un ciclo while che legge, riga per riga, il contenuto del file databases e, per ognuna, esegue il comando show tables:
while read line do command="mysql -u utente -ppassword -e 'use $line; show tables'" eval $command | grep -v "Tables_in_*" > tables_$line done < databases
Da notare come la stringa $command venga dapprima definita in modo tale da contenere il valore della variabile $line e successivamente venga eseguita sottoforma di comando mediante la direttiva eval.
Verifico, quindi, che il numero dei file tables_$line sia uguale al numero di database (e che quindi vi sia la ragionevole certezza che per ciascun database sia stato individuato il nome delle tabelle di cui è composto):
num_databases=`cat databases | wc -l` ls | grep "tables_*" > table num_tables=`cat table | wc -l` if [ $num_databases -eq $num_tables ];then
Infine, per ciascuna tabella di ciascun database, lancio la query mysql -u utente -ppassword -e ‘use $database; select * from $line LIMIT 1’, definita come stringa ed eseguita mediante eval (come visto in precedenza):
for i in {1..19} do database=`cat databases | sed -n "$i p"` echo ".......tables for $database......." cat tables_"$database" | while read line do echo $line command="mysql -u utente -ppassword -e 'use $database; select * from $line LIMIT 1'" echo "....Executing $command...." >> result eval "$command" | tee -a result echo "....End executing $command ...." >> result done echo ".......end tables for $database......." done fi
Da notare come, nel mio caso, vi sia un totale di 19 database, per cui ho utilizzato un semplice ciclo for così definito:
for i in {1..19}
Nulla però vieta di usare come upper bound la variabile $num_databases o $num_tables.
Infine rendiamo eseguibile lo scrip (che ho denominato, per semplicità, my.sh):
[root@server ~]# chmod +x my.sh
ed eseguiamolo:
[root@server ~]# ./my.sh
E’ tutto, alla prossima.