Wie führe ich einen MySQL-Befehl aus einem Shell-Skript aus?


131

Wie kann ich einen SQL-Befehl über ein Shell-Skript ausführen, damit ich ihn automatisieren kann?

Ich möchte Daten, die ich in einer SQL-Datei gesammelt habe, mithilfe eines Shell-Skripts wiederherstellen. Ich möchte eine Verbindung zu einem Server herstellen und Daten wiederherstellen. Der Befehl funktioniert, wenn er separat über die SSH-Befehlszeile ausgeführt wird.

Dies ist der Befehl, den ich benutze:

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

Dies ist der Shell-Skriptcode, der die Datei erstellt ds_fbids.sqlund in MySQL weiterleitet.

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

Was ist der richtige Weg, um dies zu tun?

Antworten:


176

Sie müssen das -pFlag verwenden, um ein Passwort zu senden. Und es ist schwierig, weil zwischen -pdem Passwort kein Leerzeichen stehen darf .

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

Wenn Sie ein Leerzeichen verwenden, nachdem -pder MySQL-Client Sie interaktiv zur Eingabe des Kennworts auffordert, interpretiert er das nächste Befehlsargument als Datenbanknamen:

$ 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'

Eigentlich bevorzuge ich es, den Benutzer und das Passwort in ~ / .my.cnf zu speichern, damit ich es überhaupt nicht in die Befehlszeile einfügen muss:

[client]
user = root
password = XXXXXXXX

Dann:

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

Zu Ihrem Kommentar:

Ich führe ständig MySQL-Befehle im Batch-Modus wie oben in der Befehlszeile und in Shell-Skripten aus. Es ist schwer zu diagnostizieren, was mit Ihrem Shell-Skript nicht stimmt, da Sie weder das genaue Skript noch eine Fehlerausgabe freigegeben haben. Ich schlage vor, Sie bearbeiten Ihre ursprüngliche Frage oben und geben Beispiele dafür, was schief geht.

Auch wenn ich ein Shell-Skript behebe, verwende ich das -xFlag, damit ich sehen kann, wie es jeden Befehl ausführt:

$ bash -x myscript.sh

Vielen Dank für eine schnelle Antwort. Ich war müde, als ich das Passwort in die Kommandozeile selbst eingegeben habe. Das eigentliche Problem ist, dass ich diesen Befehl in die .sh-Datei setze und dann dieses Shell-Skript ausführe. Der Befehl in der Datei wird nicht in der Befehlszeile ausgeführt, aber der gleiche Befehl funktioniert einwandfrei, wenn ich nur den Befehl in der Befehlszeile ausführe.
MUFC

+ mysql -h dbservername -u user-name -ppassword dbname</br> : No such file or directoryids.sql</br> + $'\r' : command not found2:Dies ist die Fehlermeldung, die ich erhalten habe
MUFC

Ok, dann würde ich schließen, dass sich Ihr aktuelles Arbeitsverzeichnis nicht dort befindet, wo sich die Datei ids.sql befindet. Möglicherweise haben Sie auch Zeilenumbrüche in Ihr Skript eingebettet.
Bill Karwin

Ich habe nach jedem Befehl neue Zeilen in mein Shell-Skript eingebettet. Alles, was mein Shell-Skript enthält, sind 3 Befehlszeilenbefehle, die ich nicht separat ausführen möchte. Deshalb habe ich ein Shell-Skript erstellt, damit sie ohne mein Eingreifen ausgeführt werden, und bei jedem Befehl eine neue Zeile eingefügt. Ist das ein Problem?
MUFC

Am besten vermeiden Sie, -pwenn das Passwort null oder eine leere Zeichenfolge ist. Vielleicht können Sie Ihren Beitrag aktualisieren? :)
James Oravec

118

Verwenden Sie diese Syntax:

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

8
Ich bin von Google auf diese Seite gelangt und dies ist die Lösung, die ich erwartet habe (passend zum Titel der Frage).
Janaka R Rajapaksha

15
Weitere Details zu den Optionen aus dem Handbuch: -B dient zum Stapeln. Drucken Sie die Ergebnisse mithilfe der Registerkarte als Spaltentrennzeichen, wobei jede Zeile in einer neuen Zeile steht. Mit dieser Option verwendet MySQL die Verlaufsdatei nicht. Der Stapelmodus führt zu einem nicht tabellarischen Ausgabeformat und zum Escapezeichen von Sonderzeichen. -s ist der stille Modus. Produzieren Sie weniger Leistung. -e soll die Anweisung ausführen und beenden
wranvaud

Danke für Ihre Hilfe! :)
haotang

Könnte es mit einem Heredoc laufen?
zx1986

1
@ zx1986 Ja und Nein zu HEREDOC. Kommt darauf an, wie du es benutzen willst. Die Verwendung zum Ersetzen des "command1;command2;....;commandn"Teils dieser Antwort funktioniert nicht. Die Verwendung als Ersatz für die Verwendung der umgeleiteten Datei in der OP-Syntax kann funktionieren. Ich habe dieses Problem in meiner Antwort auf diese Frage angesprochen .
Chindraba

45

Alle vorherigen Antworten sind großartig. Wenn es sich um einen einfachen, einzeiligen SQL-Befehl handelt, den Sie ausführen möchten, können Sie auch die Option -e verwenden.

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

Abfrage in doppelten ("") Anführungszeichen war das, was ich tun muss. Danke
user3132107

Ich verstehe, und ich nehme an, Sie müssen das Semikolon am Ende der Abfrage einfügen?
Lori

19

Verwenden Sie die folgende Syntax, um ein SQL-Skript auszuführen:

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

Wenn Sie Host als localhost verwenden, müssen Sie es nicht erwähnen. Sie können dies verwenden:

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

Dies sollte für Windows und Linux funktionieren.

Wenn der Passwortinhalt ein !(Ausrufezeichen) enthält, sollten Sie einen \(Backslash) davor einfügen.


1
Wie gebe ich die Datenbank an? sollte es in -e sein, wie -e "benutze abc; source dbscript.sql"?
Abdul Muneer

9

Der Kern der Frage wurde bereits mehrmals beantwortet. Ich dachte nur, ich würde hinzufügen, dass Backticks sowohl in Shell-Scripting als auch in SQL Beaning haben. Wenn Sie sie in SQL zum Angeben eines Tabellen- oder Datenbanknamens verwenden müssen, müssen Sie sie im Shell-Skript wie folgt maskieren:

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;"

Natürlich sollte das Generieren von SQL durch verkettete Benutzereingaben (übergebene Argumente) nur durchgeführt werden, wenn Sie der Benutzereingabe vertrauen. Es wäre viel sicherer, es in eine andere Skriptsprache mit Unterstützung für Parameter zu übertragen / Zeichenfolgen zum Einfügen korrekt zu maskieren in MySQL.


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

(Verwenden Sie sql_script_filebei Bedarf den vollständigen Pfad )

Wenn Sie den Ausgang in eine Datei umleiten möchten

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

@Gus, Zunächst einmal vielen Dank für die wertvollen Kommentare. Es hat wie ein Zauber für mich funktioniert. Ich möchte, dass die Ausgabe eine Excel- oder CSV-Datei ist. Wie kann ich das erreichen? Danke im Voraus.
Ash_and_Perl

@Ash_and_Perl Ich habe nur diese Antwort bearbeitet, danke Vine nicht mir, es ist seine Antwort. Wenn Sie eine eigene Frage haben und bereits versucht haben, selbst eine Lösung zu finden , sollten Sie eine Frage erstellen. Auf diese Weise können Sie detailliert beschreiben, was Sie versucht haben, wie es fehlgeschlagen ist, und die Leute können Ihnen eine vollständige Antwort geben (und Punkte dafür bekommen!).
Gus

5

Sie haben vergessen -poder --password=(letzteres ist besser lesbar):

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

(Die Anführungszeichen sind nicht erforderlich, wenn Sie sicher sind, dass Ihre Anmeldeinformationen / Namen kein Leerzeichen oder Shell-Sonderzeichen enthalten.)

Beachten Sie, dass auch in der Manpage angegeben ist, dass die Angabe der Anmeldeinformationen in der Befehlszeile unsicher ist. Befolgen Sie also Bills Ratschläge zu my.cnf.


4

Wie bereits erwähnt, können Sie mit -p das Kennwort an den Server übergeben.

Aber ich empfehle dies:

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

Beachten Sie, dass das Passwort nicht vorhanden ist. Es würde Sie dann zur Eingabe des Passworts auffordern. Ich würde es dann eingeben. Damit Ihr Passwort nicht im Befehlszeilenverlauf des Servers angemeldet wird.

Dies ist eine grundlegende Sicherheitsmaßnahme.

Wenn die Sicherheit kein Problem darstellt, würde ich das Kennwort nur vorübergehend vom Datenbankbenutzer entfernen. Dann nach dem Import - fügen Sie es erneut hinzu.

Auf diese Weise werden andere Konten, die möglicherweise dasselbe Kennwort haben, nicht gefährdet.

Es scheint auch, dass Sie in Ihrem Shell-Skript nicht warten / prüfen, ob die zu importierende Datei tatsächlich vorhanden ist. Das Perl-Skript ist möglicherweise noch nicht fertig.


1
Sie haben den "automatisierten" Teil der Frage verpasst, und das vorübergehende Entfernen des Passworts ist eine wirklich schlechte Idee.
PointedEars

Ich habe es als "wiederherstellen" und "automatisiert" gelesen, was "automatisiert, aber nicht für immer" bedeutet. Aber wie gesagt "wenn Sicherheit kein Problem ist". Ich stimme zu - es ist eine wirklich schlechte Idee.
Sterling Hamilton

Es tut mir leid, wenn ich Verwirrung gestiftet habe. Mit "Automatisiert" habe ich zwei Perl-Skripte gemeint, mit denen die SQL-Datei generiert wird. Der Befehl zum Speichern dieser Datei in der Datenbank wird jedoch nicht vom Shell-Skript ausgeführt, funktioniert jedoch absolut, wenn ich diesen Befehl ausführe auf einer Kommandozeile. Ich möchte den Aufwand für die Ausführung dieses Befehls in der Befehlszeile verringern und ihn über das Shell-Skript selbst ausführen.
MUFC

1
Vaibav: Wenn Sie das eigentliche Shell-Skript in Ihre Frage aufnehmen könnten, könnte ich Ihnen möglicherweise weiterhelfen.
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

Verwenden

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

3

Um „Automate“ der Prozess der erzeugten Import - .sqlDatei, während all Fallen zu vermeiden, die bei dem Versuch , versteckt werden können Dateien durchlaufen stdinund stdoutnur MySQL anweisen , die erzeugte auszuführen .sqlDatei mit dem SOURCEBefehl in MySQL.

Die Syntax in der kurzen, aber ausgezeichneten Antwort von Kshitij Sood bietet den besten Ausgangspunkt. Kurz gesagt, ändern Sie den Befehl des OP gemäß der Syntax von Kshitij Sood und ersetzen Sie die darin enthaltenen Befehle durch den folgenden SOURCEBefehl:

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

Wenn der Datenbankname in der generierten .sqlDatei enthalten ist, kann er aus dem Befehl entfernt werden.

Hierbei wird davon ausgegangen, dass die generierte Datei als eigenständige Datei gültig ist .sql. Da die Datei nicht umgeleitet, weitergeleitet oder auf andere Weise von der Shell verarbeitet wird, ist es kein Problem, aufgrund der Shell eines der Zeichen in der generierten Ausgabe zu maskieren. Die Regeln in Bezug auf das, was in einem entkommen muss.sql Datei maskiert werden muss, gelten natürlich weiterhin.

Der Umgang mit Sicherheitsproblemen rund um das Kennwort in der Befehlszeile oder in einer my.cnfDatei usw. wurde in anderen Antworten mit einigen hervorragenden Vorschlägen ausführlich behandelt. Meine Lieblingsantwort von Danny behandelt dies, einschließlich des Umgangs mit dem Problem beim Umgang mit cronJobs oder irgendetwas anderem.


Um einen Kommentar (Frage?) Zu der kurzen Antwort zu adressieren, die ich erwähnt habe: Nein, sie kann nicht mit einer HEREDOC-Syntax verwendet werden, da dieser Shell-Befehl gegeben wird. HEREDOC kann in der Syntax der Umleitungsversion verwendet werden (ohne die -BseOption), da HEREDOC auf der E / A-Umleitung basiert. Wenn Sie die Funktionalität von HEREDOC benötigen, ist es besser, sie beim Erstellen einer .sqlDatei zu verwenden, auch wenn es sich um eine temporäre Datei handelt, und diese Datei als "Befehl" für die Ausführung mit der MySQL-Stapelzeile zu verwenden.

#!/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

Beachten Sie, dass Sie aufgrund der Shell-Erweiterung Shell- und Umgebungsvariablen im HEREDOC verwenden können. Der Nachteil ist, dass Sie jedem Backtick entkommen müssen. MySQL verwendet sie als Trennzeichen für Bezeichner, aber die Shell, die zuerst die Zeichenfolge erhält, verwendet sie als Trennzeichen für ausführbare Befehle. Verpassen Sie die Flucht mit einem einzigen Backtick der MySQL-Befehle, und das Ganze explodiert mit Fehlern. Das gesamte Problem kann mithilfe eines zitierten LimitString für das HEREDOC gelöst werden:

#!/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

Durch das Entfernen der Shell-Erweiterung auf diese Weise müssen die Backticks und andere Shell-Sonderzeichen nicht mehr entfernt werden. Außerdem wird die Möglichkeit entfernt, Shell- und Umgebungsvariablen darin zu verwenden. Damit entfallen die Vorteile der Verwendung eines HEREDOC im Shell-Skript.

Die andere Option besteht darin, die in Bash zulässigen mehrzeiligen Zeichenfolgen in Anführungszeichen mit der Batch-Syntaxversion (mit dem -Bse) zu verwenden. Ich kenne keine anderen Muscheln, daher kann ich nicht sagen, ob sie auch darin funktionieren. Sie müssten dies ohnehin verwenden, um mehr als eine .sqlDatei mit dem SOURCEBefehl auszuführen , da dies nicht; wie andere MySQL-Befehle durch a beendet wird und nur eine pro Zeile zulässig ist. Die mehrzeilige Zeichenfolge kann entweder in einfachen oder doppelten Anführungszeichen stehen, mit den normalen Auswirkungen auf die Shell-Erweiterung. Es hat auch die gleichen Einschränkungen wie die Verwendung der HEREDOC-Syntax für Backticks usw.

Eine potenziell bessere Lösung wäre die Verwendung einer Skriptsprache, Perl, Python usw., um die .sqlDatei wie im OP zu erstellen , und SOURCEdiese Datei mit der einfachen Befehlssyntax oben. Die Skriptsprachen sind bei der Manipulation von Zeichenfolgen viel besser als die Shell und die meisten verfügen über integrierte Verfahren, um das Zitieren und Escape-Verhalten im Umgang mit MySQL zu bewältigen.


2

Eine wichtige Überlegung für den Zugriff auf mysql über ein in cron verwendetes Shell-Skript ist, dass mysql den angemeldeten Benutzer überprüft, um eine zu ladende .my.cnf zu ermitteln.

Das funktioniert mit cron nicht. Es kann auch verwirrend werden, wenn Sie su / sudo verwenden, da der angemeldete Benutzer möglicherweise nicht der Benutzer ist, als den Sie ausgeführt werden.

Ich benutze so etwas wie:

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

Stellen Sie einfach sicher, dass Benutzer- und Gruppenbesitz und -berechtigungen in der Datei .my.cnf richtig und genau festgelegt sind.


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

Wie führe ich eine Befehlszeile mit einem sicheren Passwort aus? benutze den Konfigurationseditor !!!

Ab MySQL 5.6.6 können Sie das Passwort in einer Konfigurationsdatei speichern und dann solche CLI-Befehle ausführen ....

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

--login-path ersetzt Variablen ... Host, Benutzer UND Passwort. ausgezeichnet richtig!



0

Ich habe ein Shell-Skript geschrieben, das Daten aus der Eigenschaftendatei liest und dann ein MySQL-Skript für ein Shell-Skript ausführt. Dies zu teilen kann anderen helfen.

#!/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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.