Comment exécuter une commande MySQL à partir d'un script shell?

131

Comment puis-je exécuter une commande SQL via un script shell afin de la rendre automatisée?

Je souhaite restaurer les données que j'ai collectées dans un fichier SQL à l'aide d'un script shell. Je souhaite me connecter à un serveur et restaurer des données. La commande fonctionne lorsqu'elle est exécutée séparément via la ligne de commande SSH.

C'est la commande que j'utilise:

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

C'est le code de script shell qui crée le fichier ds_fbids.sqlet le transforme en 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

Quelle est la bonne façon de procéder?

MUFC
la source

Réponses:

176

Vous devez utiliser le -pdrapeau pour envoyer un mot de passe. Et c'est délicat car vous ne devez pas avoir d'espace entre -pet le mot de passe.

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

Si vous utilisez un espace après -pque le client mysql vous invite interactivement pour le mot de passe, puis il interprète l'argument de commande suivant comme un nom de base de données:

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

En fait, je préfère stocker l'utilisateur et le mot de passe dans ~ / .my.cnf pour ne pas avoir à le mettre du tout sur la ligne de commande:

[client]
user = root
password = XXXXXXXX

Ensuite:

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

Re votre commentaire:

J'exécute des commandes mysql en mode batch comme ci-dessus sur la ligne de commande et dans les scripts shell tout le temps. Il est difficile de diagnostiquer ce qui ne va pas avec votre script shell, car vous n'avez pas partagé le script exact ni aucune sortie d'erreur. Je vous suggère de modifier votre question initiale ci-dessus et de fournir des exemples de ce qui ne va pas.

De plus, lorsque je dépanne un script shell, j'utilise l' -xindicateur afin de voir comment il exécute chaque commande:

$ bash -x myscript.sh
Bill Karwin
la source
Merci pour une réponse rapide. Je suis fatigué en mettant le mot de passe dans la ligne de commande elle-même. Le vrai problème est que je mets cette commande dans un fichier .sh, puis j'exécute ce script shell. La commande dans le fichier n'est pas exécutée en ligne de commande, mais la même commande fonctionne parfaitement bien lorsque j'exécute uniquement la commande en ligne de commande.
MUFC
+ mysql -h dbservername -u user-name -ppassword dbname</br> : No such file or directoryids.sql</br> + $'\r' : command not found2:C'est le message d'erreur que j'ai reçu
MUFC
Ok, alors j'en déduire que votre répertoire de travail actuel n'est pas où se trouve le fichier ids.sql. Vous pouvez également avoir intégré des nouvelles lignes dans votre script.
Bill Karwin
J'ai de nouvelles lignes intégrées dans mon script shell après chaque commande. Tout ce que mon script shell contient sont 3 commandes de ligne de commande que je ne veux pas exécuter séparément, j'ai donc créé un script shell pour les faire fonctionner sans mon intervention et j'ai mis une nouvelle ligne après chaque commande. Est-ce que cela pose problème?
MUFC
mieux éviter -psi le mot de passe est une chaîne nulle ou vide, vous pouvez peut-être mettre à jour votre message? :)
James Oravec
118

Utilisez cette syntaxe:

mysql -u $user -p$passsword -Bse "command1;command2;....;commandn"
Kshitij Sood
la source
8
J'ai été redirigé vers cette page de google et c'est la solution que j'attendais (correspondant au titre de la question).
Janaka R Rajapaksha
16
Quelques détails supplémentaires sur les options du manuel: -B est pour le lot, imprimez les résultats en utilisant l'onglet comme séparateur de colonne, avec chaque ligne sur une nouvelle ligne. Avec cette option, mysql n'utilise pas le fichier historique. Le mode batch entraîne un format de sortie non tabulaire et l'échappement des caractères spéciaux. -s est le mode silencieux. Produisez moins de rendement. -e consiste à exécuter l'instruction et à quitter
wranvaud
Merci de votre aide! :)
haotang
Pourrait-il fonctionner avec un heredoc?
zx1986
1
@ zx1986 Oui et non, à HEREDOC. Cela dépend de la façon dont vous comptez l'utiliser. L'utiliser pour remplacer la "command1;command2;....;commandn"partie de cette réponse ne fonctionnera pas. Son utilisation pour remplacer l'utilisation du fichier redirigé dans la syntaxe de l'OP peut fonctionner. J'ai abordé ce problème dans ma réponse à cette question.
Chindraba
45

Toutes les réponses précédentes sont excellentes. S'il s'agit d'une simple commande sql d'une ligne que vous souhaitez exécuter, vous pouvez également utiliser l'option -e.

mysql -h <host> -u<user> -p<password> database -e \
  "SELECT * FROM blah WHERE foo='bar';"
Jericon
la source
La requête entre guillemets doubles ("") était ce que je devais faire. Merci
user3132107
Je vois, et je suppose que vous devez inclure le point-virgule à la fin de la requête?
Lori
19

Comment exécuter un script SQL, utilisez cette syntaxe:

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

Si vous utilisez host comme localhost, vous n'avez pas besoin de le mentionner. Vous pouvez utiliser ceci:

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

Cela devrait fonctionner pour Windows et Linux.

Si le contenu du mot de passe contient un !(point d'exclamation), vous devez ajouter une \(barre oblique inverse) devant lui.

Milinda Bandara
la source
1
Comment spécifier la base de données? devrait-il être à l'intérieur de -e, comme -e "use abc; source dbscript.sql"?
Abdul Muneer
9

Le cœur de la question a déjà reçu une réponse à plusieurs reprises, j'ai juste pensé ajouter que les backticks (s) ont des beaning à la fois dans le script shell et SQL. Si vous avez besoin de les utiliser dans SQL pour spécifier un nom de table ou de base de données, vous devrez les échapper dans le script shell comme ceci:

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

Bien sûr, la génération de SQL via une entrée utilisateur concaténée (arguments passés) ne devrait pas être effectuée à moins que vous ne fassiez confiance à l'entrée utilisateur.Il serait beaucoup plus sûr de le mettre dans un autre langage de script avec prise en charge des paramètres / échapper correctement les chaînes pour l'insertion dans MySQL.

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

(utilisez le chemin complet pour sql_script_filesi nécessaire)

Si vous souhaitez rediriger la sortie vers un fichier

mysql -h "hostname" -u usr_name -pPASSWD "db_name" < sql_script_file > out_file
vigne
la source
@Gus, tout d'abord merci pour les précieux commentaires. Cela a fonctionné comme un charme pour moi. Je veux que la sortie soit un fichier Excel ou .csv. comment puis-je y parvenir. Merci d'avance.
Ash_and_Perl
@Ash_and_Perl J'ai seulement édité cette réponse, merci Vine pas moi, c'est sa réponse. Si vous avez une question personnelle et que vous avez déjà essayé de trouver une solution par vous-même , je vous suggère de créer une question. De cette façon, vous pouvez détailler ce que vous avez essayé, comment cela a échoué, et les gens peuvent vous donner une réponse complète et complète (et obtenir des points pour cela!).
Gus
5

Vous avez oublié -pou --password=(ce dernier est mieux lisible):

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

(Les guillemets ne sont pas nécessaires si vous êtes sûr que vos informations d'identification / noms ne contiennent pas d'espace ou de caractères spéciaux du shell.)

Notez que la page de manuel indique également que la fourniture des informations d'identification sur la ligne de commande n'est pas sécurisée. Alors suivez les conseils de Bill concernant my.cnf.

Oreilles pointues
la source
4

Comme indiqué précédemment, vous pouvez utiliser -p pour transmettre le mot de passe au serveur.

Mais je recommande ceci:

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

Notez que le mot de passe n'est pas là. Il vous demandera alors le mot de passe. Je voudrais alors le taper. Pour que votre mot de passe ne soit pas connecté à l'historique de la ligne de commande des serveurs.

Il s'agit d'une mesure de sécurité de base.

Si la sécurité n'est pas un problème, je supprimerais temporairement le mot de passe de l'utilisateur de la base de données. Ensuite, après l'importation, ajoutez-le à nouveau.

De cette façon, tous les autres comptes que vous pourriez avoir et partageant le même mot de passe ne seront pas compromis.

Il semble également que dans votre script shell, vous n'attendez pas / ne vérifiez pas si le fichier que vous essayez d'importer existe réellement. Le script perl n'est peut-être pas encore terminé.

Sterling Hamilton
la source
1
Vous avez manqué la partie "automatisée" de la question et la suppression temporaire du mot de passe est une très mauvaise idée.
PointedEars
Je l'ai lu comme "restaurer" et "automatisé" qui signifie "automatisé mais pas pour toujours". Mais comme je l'ai dit "si la sécurité n'est pas une préoccupation". Je suis d'accord - c'est vraiment une mauvaise idée.
Sterling Hamilton
Je suis désolé si j'ai créé de la confusion. Ce que je voulais dire par automatisé, c'est que j'ai deux scripts perl qui sont utilisés pour générer le fichier .sql, mais la commande pour vider ce fichier dans DB n'est pas exécutée par le script shell, mais cela fonctionne absolument file si j'exécute cette commande sur une ligne de commande. Je veux éliminer l'effort d'exécuter cette commande sur la ligne de commande et l'exécuter via le script shell lui-même.
MUFC
1
Vaibav: si vous pouviez mettre le script shell dans votre question, je pourrais peut-être vous aider davantage.
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

Utilisation

echo "your sql script;" | mysql -u -p -h db_name
Senninha
la source
3

Pour "automatiser" le processus d'importation du .sqlfichier généré , tout en évitant tous les pièges qui peuvent être cachés en essayant de faire passer des fichiers stdinet stdout, dites simplement à MySQL d'exécuter le .sqlfichier généré en utilisant la SOURCEcommande dans MySQL.

La syntaxe de la réponse courte, mais excellente, de Kshitij Sood , constitue le meilleur point de départ. En bref, modifiez la commande de l'OP selon la syntaxe de Kshitij Sood et remplacez les commandes en cela par la SOURCEcommande:

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

Si le nom de la base de données est inclus dans le .sqlfichier généré , il peut être supprimé de la commande.

La présomption ici est que le fichier généré est valide en tant que .sqlfichier seul. En ne faisant pas que le fichier soit redirigé, redirigé ou de toute autre manière géré par le shell, il n'y a aucun problème avec le besoin d'échapper à l'un des caractères de la sortie générée à cause du shell. Les règles relatives à ce qui doit être échappé dans un .sqlfichier, bien sûr, s'appliquent toujours.

Comment traiter les problèmes de sécurité autour du mot de passe sur la ligne de commande, ou dans un my.cnffichier, etc., a été bien abordé dans d'autres réponses, avec d'excellentes suggestions. Ma réponse préférée , de Danny , couvre cela, y compris la façon de gérer le problème lors du crontravail ou de toute autre chose.


Pour répondre à un commentaire (question?) Sur la réponse courte que j'ai mentionnée: Non, elle ne peut pas être utilisée avec une syntaxe HEREDOC, car cette commande shell est donnée. HEREDOC peut être utilisé dans la syntaxe de la version de redirection , (sans l' -Bseoption), car la redirection d'E / S est ce sur quoi HEREDOC est construit. Si vous avez besoin de la fonctionnalité de HEREDOC, il serait préférable de l'utiliser dans la création d'un .sqlfichier, même s'il s'agit d'un fichier temporaire, et d'utiliser ce fichier comme "commande" à exécuter avec la ligne de commandes 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

Gardez à l'esprit qu'en raison de l'expansion du shell, vous pouvez utiliser des variables de shell et d'environnement dans HEREDOC. L' inconvénient est que vous devez échapper à chaque backtick. MySQL les utilise comme délimiteurs pour les identificateurs mais le shell, qui obtient la chaîne en premier, les utilise comme délimiteurs de commandes exécutables. Manquez l'évasion sur un seul backtick des commandes MySQL, et le tout explose avec des erreurs. L'ensemble du problème peut être résolu en utilisant une LimitString citée pour le 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

La suppression de l'extension du shell de cette façon élimine le besoin d'échapper aux backticks et aux autres caractères spéciaux du shell. Il supprime également la possibilité d'utiliser des variables de shell et d'environnement en son sein. Cela supprime à peu près les avantages de l'utilisation d'un HEREDOC dans le script shell pour commencer.

L'autre option consiste à utiliser les chaînes entre guillemets multilignes autorisées dans Bash avec la version de la syntaxe du lot (avec le -Bse). Je ne connais pas d'autres coques, donc je ne peux pas dire si elles y fonctionnent également. Vous devrez de toute façon l'utiliser pour exécuter plus d'un .sqlfichier avec la SOURCEcommande, car cela n'est pas terminé par un ;comme le sont les autres commandes MySQL, et un seul est autorisé par ligne. La chaîne multiligne peut être entre guillemets simples ou doubles, avec les effets normaux sur l'expansion du shell. Il comporte également les mêmes mises en garde que l'utilisation de la syntaxe HEREDOC pour les backticks, etc.

Une solution potentiellement meilleure serait d'utiliser un langage de script, Perl, Python, etc., pour créer le .sqlfichier, comme l'a fait l'OP, et SOURCEce fichier en utilisant la syntaxe de commande simple en haut. Les langages de script sont bien meilleurs pour la manipulation de chaînes que le shell, et la plupart ont des procédures intégrées pour gérer les guillemets et les échappements nécessaires lors de l'utilisation de MySQL.

Chindraba
la source
2

Une considération importante pour accéder à mysql à partir d'un script shell utilisé dans cron, est que mysql regarde l'utilisateur connecté pour déterminer un .my.cnf à charger.

Cela ne fonctionne pas avec cron. Cela peut également prêter à confusion si vous utilisez su / sudo car l'utilisateur connecté n'est peut-être pas l'utilisateur sous lequel vous exécutez.

J'utilise quelque chose comme:

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

Assurez-vous simplement que la propriété et les autorisations des utilisateurs et des groupes sont définies de manière appropriée et stricte sur le fichier .my.cnf.

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

v_path=/etc/database_jobs
v_cnt=0

MAILTO="[email protected] [email protected] [email protected]"
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
kartavya soni
la source
0
mysql_config_editor set --login-path=storedPasswordKey --host=localhost --user=root --password

Comment exécuter une ligne de commande avec un mot de passe sécurisé? utilisez l'éditeur de configuration !!!

Depuis mysql 5.6.6, vous pouvez stocker le mot de passe dans un fichier de configuration, puis exécuter des commandes cli comme celle-ci ...

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

--login-path remplace les variables ... hôte, utilisateur ET mot de passe. excellent droit!

Artistan
la source
0

J'ai écrit un script shell qui lira les données du fichier de propriétés, puis exécutera le script mysql sur le script shell. partager cela peut aider les autres.

#!/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
flopcoder
la source