Come eseguire un comando MySQL da uno script di shell?


131

Come posso eseguire un comando SQL tramite uno script della shell in modo da poterlo automatizzare?

Voglio ripristinare i dati raccolti in un file SQL usando uno script di shell. Voglio collegarmi a un server e ripristinare i dati. Il comando funziona se eseguito separatamente tramite la riga di comando SSH.

Questo è il comando che uso:

mysql -h "server-name" -u root "password" "database-name" < "filename.sql"

Questo è il codice dello script della shell che crea il file ds_fbids.sqle lo convoglia in mysql.

perl fb_apps_frm_fb.pl
perl fb_new_spider.pl ds_fbids.txt ds_fbids.sql
mysql -h dbservername -u username -ppassword dbname < ds_fbids.sql

Qual è il modo corretto per farlo?

Risposte:


176

Devi usare il -pflag per inviare una password. Ed è complicato perché non devi avere spazio tra -pe la password.

$ mysql -h "server-name" -u "root" "-pXXXXXXXX" "database-name" < "filename.sql"

Se si utilizza uno spazio dopo -pche il client mysql richiede la password in modo interattivo, quindi interpreta il successivo argomento del comando come nome-database:

$ mysql -h "server-name" -u "root" -p "XXXXXXXX" "database-name" < "filename.sql"
Enter password: <you type it in here>
ERROR 1049 (42000): Unknown database 'XXXXXXXX'

In realtà, preferisco memorizzare l'utente e la password in ~ / .my.cnf, quindi non devo assolutamente inserirli nella riga di comando:

[client]
user = root
password = XXXXXXXX

Poi:

$ mysql -h "server-name" "database-name" < "filename.sql"

Re il tuo commento:

Eseguo sempre comandi mysql in modalità batch come sopra nella riga di comando e negli script di shell. È difficile diagnosticare cosa c'è di sbagliato nel tuo script di shell, perché non hai condiviso lo script esatto o qualsiasi output di errore. Ti suggerisco di modificare la domanda originale sopra e fornire esempi di cosa non va.

Inoltre, quando sto risolvendo uno script di shell, uso il -xflag in modo da poter vedere come sta eseguendo ogni comando:

$ bash -x myscript.sh

Grazie per una rapida risposta Mi sono stancato inserendo la password nella stessa riga di comando. Il vero problema è che sto inserendo questo comando nel file .sh e quindi eseguendo questo script di shell. Il comando nel file non viene eseguito sulla riga di comando, ma lo stesso comando funziona perfettamente quando eseguo solo il comando sulla riga di comando.
MUFC

+ mysql -h dbservername -u user-name -ppassword dbname</br> : No such file or directoryids.sql</br> + $'\r' : command not found2:Questo è il messaggio di errore che ho ricevuto
MUFC

Ok, quindi desidero dedurre che la tua attuale directory di lavoro non è dove si trova il file ids.sql. Inoltre potresti avere delle nuove righe incorporate nel tuo script.
Bill Karwin,

Ho nuove righe incorporate nel mio script shell dopo ogni comando. Tutto ciò che contiene il mio script di shell sono 3 comandi da riga di comando che non voglio eseguire separatamente, quindi ho creato uno script di shell per farli funzionare senza il mio intervento e ho inserito Newline dopo ogni comando. Questo sta causando problemi?
MUFC

meglio evitare -pse la password è null o stringa vuota, forse puoi aggiornare il tuo post? :)
James Oravec,

118

Usa questa sintassi:

mysql -u $user -p$passsword -Bse "command1;command2;....;commandn"

8
Sono arrivato a questa pagina da Google e questa è la soluzione che mi aspettavo (corrispondente al titolo della domanda).
Janaka R Rajapaksha,

15
Alcuni maggiori dettagli sulle opzioni del manuale: -B è per batch, stampa i risultati usando tab come separatore di colonna, con ogni riga su una nuova riga. Con questa opzione, mysql non utilizza il file cronologico. La modalità batch comporta un formato di output non tabulare e la escape di caratteri speciali. -s è la modalità silenziosa. Produce meno output. -e deve eseguire la dichiarazione ed uscire
wranvaud

Grazie per l'aiuto! :)
haotang il

Potrebbe correre con un ereditario?
zx1986,

1
@ zx1986 Sì e No, a HEREDOC. Dipende da come intendi usarlo. Usarlo per sostituire la "command1;command2;....;commandn"parte di questa risposta non funzionerà. Usarlo per sostituire l'uso del file reindirizzato nella sintassi dell'OP può funzionare. Ho affrontato questo problema nella mia risposta a questa domanda.
Chindraba,

45

Tutte le risposte precedenti sono fantastiche. Se si desidera eseguire un comando sql di una riga semplice, è possibile utilizzare anche l'opzione -e.

mysql -h <host> -u<user> -p<password> database -e \
  "SELECT * FROM blah WHERE foo='bar';"

Query tra virgolette doppie ("") era ciò che dovevo fare. Grazie
user3132107,

Vedo, e presumo che sia necessario includere il punto e virgola alla fine della query?
Lori

19

Come eseguire uno script SQL, utilizzare questa sintassi:

mysql --host= localhost --user=root --password=xxxxxx  -e "source dbscript.sql"

Se usi host come localhost non devi menzionarlo. Puoi usare questo:

mysql --user=root --password=xxxxxx  -e "source dbscript.sql"

Questo dovrebbe funzionare per Windows e Linux.

Se il contenuto della password contiene un !(punto esclamativo) è necessario aggiungere una \(barra rovesciata) davanti.


1
Come specificare il database? dovrebbe essere all'interno di -e, come -e "usa abc; source dbscript.sql"?
Abdul Muneer,

9

Il nocciolo della domanda ha già ricevuto diverse risposte, ho solo pensato che avrei aggiunto che i backtick si sono uniti sia allo scripting della shell che a SQL. Se è necessario utilizzarli in SQL per specificare un nome di tabella o di database, è necessario evitarli nello script della shell in questo modo:

mysql -p=password -u "root" -Bse "CREATE DATABASE \`${1}_database\`;
CREATE USER '$1'@'%' IDENTIFIED BY '$2';
GRANT ALL PRIVILEGES ON `${1}_database`.* TO '$1'@'%' WITH GRANT OPTION;"

Ovviamente, la generazione di SQL tramite input utente concatenato (argomenti passati) non dovrebbe essere eseguita a meno che non ci si fidi dell'input dell'utente. Sarebbe molto più sicuro metterlo in un altro linguaggio di scripting con supporto per parametri / fuga corretta delle stringhe per l'inserimento in MySQL.


5
mysql -h "hostname" -u usr_name -pPASSWD "db_name" < sql_script_file

(utilizzare il percorso completo per sql_script_filese necessario)

Se vuoi reindirizzare l'output su un file

mysql -h "hostname" -u usr_name -pPASSWD "db_name" < sql_script_file > out_file

@Gus, innanzitutto grazie per i preziosi commenti. Ha funzionato come un incanto per me. Voglio che l'output sia un file Excel o .csv. come posso farlo. Grazie in anticipo.
Ash_and_Perl,

@Ash_and_Perl Ho solo modificato questa risposta, grazie a Vine non a me, è la sua risposta. Se hai una tua domanda e hai già provato a trovare una soluzione da solo , ti suggerisco di creare una domanda. In questo modo puoi dettagliare cosa hai provato, come è fallito e le persone possono darti una risposta completa e completa (e ottenere punti per questo!).
Gus,

5

Hai dimenticato -po --password=(quest'ultimo è meglio leggibile):

mysql -h "$server_name" "--user=$user" "--password=$password" "--database=$database_name" < "filename.sql"

(Le virgolette non sono necessarie se si è certi che le proprie credenziali / nomi non contengano spazi o caratteri speciali della shell.)

Si noti che anche la manpage afferma che fornire le credenziali sulla riga di comando non è sicuro. Quindi segui i consigli di Bill su my.cnf.


4

Come indicato prima, puoi usare -p per passare la password al server.

Ma io consiglio questo:

mysql -h "hostaddress" -u "username" -p "database-name" < "sqlfile.sql"

Si noti che la password non è presente. Ti chiederà quindi la password. Vorrei quindi inserirlo. In modo che la password non venga registrata nella cronologia della riga di comando del server.

Questa è una misura di sicurezza di base.

Se la sicurezza non è un problema, rimuoverei temporaneamente la password dall'utente del database. Quindi, dopo l'importazione, aggiungilo nuovamente.

In questo modo qualsiasi altro account che possiedi che condivida la stessa password non verrebbe compromesso.

Sembra anche che nel tuo script shell non stai aspettando / controllando per vedere se il file che stai cercando di importare esiste effettivamente. Lo script perl potrebbe non essere ancora finito.


1
Hai perso la parte "automatizzata" della domanda e rimuovere temporaneamente la password è un'idea davvero negativa.
Orecchie appuntite

L'ho letto come "ripristino" e "automatizzato" che significa "automatizzato ma non per sempre". Ma come ho detto "se la sicurezza non è un problema". Sono d'accordo - è davvero una cattiva idea.
Sterling Hamilton,

Mi dispiace se ho creato confusione. Quello che intendevo per automatizzato è che ho due script perl che sono usati per generare il file .sql, ma il comando per scaricare quel file nel DB non è eseguito dallo script della shell, ma funziona assolutamente se eseguo quel comando su una riga di comando. Voglio eliminare lo sforzo di eseguire quel comando dalla riga di comando ed eseguirlo attraverso lo script della shell stesso.
MUFC

1
Vaibav: se potessi inserire l'attuale script di shell all'interno della tua domanda, potrei essere in grado di aiutarti ulteriormente.
Sterling Hamilton,

perl fb_apps_frm_fb.pl</br> perl fb_new_spider.pl ds_fbids.txt ds_fbids.sql` </br>mysql -h dbservername -u username -ppassword dbname < ds_fbids.sql
MUFC

3

Uso

echo "your sql script;" | mysql -u -p -h db_name

3

Per "automatizzare" il processo di importazione del .sqlfile generato , evitando tutte le trappole che possono essere nascoste nel tentativo di passare i file stdine stdout, basta dire a MySQL di eseguire il .sqlfile generato usando il SOURCEcomando in MySQL.

La sintassi nella risposta breve, ma eccellente , di Kshitij Sood , fornisce il miglior punto di partenza. In breve, modifica il comando dell'OP in base alla sintassi di Kshitij Sood e sostituisci i comandi in quello con il SOURCEcomando:

#!/bin/bash
mysql -u$user -p$password $dbname -Bse "SOURCE ds_fbids.sql
SOURCE ds_fbidx.sql"

Se il nome del database è incluso nel .sqlfile generato , può essere eliminato dal comando.

La presunzione qui è che il file generato sia valido come .sqlfile da solo. Non avendo il file reindirizzato, reindirizzato o gestito in altro modo dalla shell, non vi è alcun problema con la necessità di sfuggire a nessuno dei caratteri nell'output generato a causa della shell. Le regole relative a ciò che deve essere evaso in un .sqlfile, ovviamente, si applicano comunque.

Come affrontare i problemi di sicurezza relativi alla password nella riga di comando, o in un my.cnffile, ecc., È stato ben affrontato in altre risposte, con alcuni suggerimenti eccellenti. La mia risposta preferita , da Danny , copre questo, incluso come gestire il problema quando si tratta di cronlavori o altro.


Per rispondere a un commento (domanda?) Sulla risposta breve che ho citato: No, non può essere usato con una sintassi HEREDOC, dato che viene dato quel comando shell. HEREDOC può essere utilizzato nella sintassi della versione di reindirizzamento , (senza l' -Bseopzione), poiché il reindirizzamento I / O è ciò su cui è costruito HEREDOC. Se hai bisogno della funzionalità di HEREDOC, sarebbe meglio usarlo nella creazione di un .sqlfile, anche se è temporaneo, e usare quel file come "comando" per eseguire con la linea batch di MySQL.

#!/bin/bash
cat >temp.sql <<SQL_STATEMENTS
...
SELECT \`column_name\` FROM \`table_name\` WHERE \`column_name\`='$shell_variable';
...
SQL_STATEMENTS
mysql -u $user -p$password $db_name -Be "SOURCE temp.sql"
rm -f temp.sql

Tenere presente che a causa dell'espansione della shell è possibile utilizzare variabili shell e ambiente all'interno di HEREDOC. Il rovescio della medaglia è che devi sfuggire a ogni backtick. MySQL li usa come delimitatori per gli identificatori ma la shell, che ottiene per prima la stringa, li usa come delimitatori di comandi eseguibili. Perdere la fuga su un singolo backtick dei comandi MySQL e il tutto esplode con errori. L'intero problema può essere risolto utilizzando un LimitString citato per HEREDOC:

#!/bin/bash
cat >temp.sql <<'SQL_STATEMENTS'
...
SELECT `column_name` FROM `table_name` WHERE `column_name`='constant_value';
...
SQL_STATEMENTS
mysql -u $user -p$password $db_name -Be "SOURCE temp.sql"
rm -f temp.sql

Rimuovere l'espansione della shell in questo modo elimina la necessità di sfuggire ai backtick e ad altri caratteri speciali della shell. Rimuove inoltre la possibilità di utilizzare al suo interno variabili di shell e ambiente. Questo praticamente toglie i vantaggi dell'utilizzo di un HEREDOC all'interno dello script della shell per cominciare.

L'altra opzione è utilizzare le stringhe tra virgolette multilinea consentite in Bash con la versione della sintassi batch (con il -Bse). Non conosco altri gusci, quindi non posso dire se funzionano anche lì. Dovresti usarlo per eseguire più di un .sqlfile con il SOURCEcomando comunque, poiché questo non è terminato da un ;come lo sono altri comandi MySQL e ne è consentito solo uno per riga. La stringa a più righe può essere virgoletta singola o doppia, con i normali effetti sull'espansione della shell. Ha anche le stesse avvertenze dell'uso della sintassi HEREDOC per i backtick, ecc.

Una soluzione potenzialmente migliore sarebbe quella di utilizzare un linguaggio di scripting, Perl, Python, ecc., Per creare il .sqlfile, come ha fatto l'OP, e SOURCEquel file usando la semplice sintassi dei comandi in alto. I linguaggi di scripting sono molto più efficaci nella manipolazione delle stringhe rispetto alla shell, e la maggior parte ha procedure integrate per gestire le quotazioni e gli escape necessari quando si ha a che fare con MySQL.


2

Una considerazione importante per l'accesso a mysql da uno script di shell usato in cron, è che mysql guarda l'utente che ha effettuato l'accesso per determinare un .my.cnf da caricare.

Questo non funziona con cron. Può anche creare confusione se si utilizza su / sudo poiché l'utente che ha effettuato l'accesso potrebbe non essere l'utente con cui si esegue.

Uso qualcosa del tipo:

mysql --defaults-extra-file=/path/to/specific/.my.cnf -e 'SELECT something FROM sometable'

Assicurati solo che la proprietà e le autorizzazioni dell'utente e del gruppo siano impostate in modo appropriato e strettamente sul file .my.cnf.


1
#!/bin/sh
#Procedures = update
#Scheduled at : Every 00.05 

v_path=/etc/database_jobs
v_cnt=0

MAILTO="indd@abc.in joanson@abc.in sturt@abc.in"
touch "$v_path/db_db_log.log"

#test
mysql -uusername -ppassword -h111.111.111.111 db_name -e "CALL functionName()" > $v_path/db_db_log.log 2>&1
if [ "$?" -eq 0 ]
  then
   v_cnt=`expr $v_cnt + 1`
  mail -s "db Attendance Update has been run successfully" $MAILTO < $v_path/db_db_log.log
 else
   mail -s "Alert : db Attendance Update has been failed" $MAILTO < $v_path/db_db_log.log
   exit
fi

0
mysql_config_editor set --login-path=storedPasswordKey --host=localhost --user=root --password

Come eseguo una riga di comando con una password sicura ?? usa l'editor di configurazione !!!

A partire da mysql 5.6.6 è possibile memorizzare la password in un file di configurazione e quindi eseguire comandi cli in questo modo ....

mysql --login-path=storedPasswordKey ....

--login-path sostituisce le variabili ... host, user AND password. eccellente vero!



0

Ho scritto uno script shell che leggerà i dati dal file delle proprietà e quindi eseguirà lo script mysql sullo script shell. condividere questo può aiutare gli altri.

#!/bin/bash
    PROPERTY_FILE=filename.properties

    function getProperty {
       PROP_KEY=$1
       PROP_VALUE=`cat $PROPERTY_FILE | grep "$PROP_KEY" | cut -d'=' -f2`
       echo $PROP_VALUE
    }

    echo "# Reading property from $PROPERTY_FILE"
    DB_USER=$(getProperty "db.username")
    DB_PASS=$(getProperty "db.password")
    ROOT_LOC=$(getProperty "root.location")
    echo $DB_USER
    echo $DB_PASS
    echo $ROOT_LOC
    echo "Writing on DB ... "
    mysql -u$DB_USER -p$DB_PASS dbname<<EOFMYSQL

    update tablename set tablename.value_ = "$ROOT_LOC" where tablename.name_="Root directory location";
    EOFMYSQL
    echo "Writing root location($ROOT_LOC) is done ... "
    counter=`mysql -u${DB_USER} -p${DB_PASS} dbname -e "select count(*) from tablename where tablename.name_='Root directory location' and tablename.value_ = '$ROOT_LOC';" | grep -v "count"`;

    if [ "$counter" = "1" ]
    then
    echo "ROOT location updated"
    fi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.