Как выполнить команду MySQL из сценария оболочки?

131

Как я могу выполнить команду SQL через сценарий оболочки, чтобы сделать ее автоматизированной?

Я хочу восстановить данные, собранные в файле SQL, с помощью сценария оболочки. Я хочу подключиться к серверу и восстановить данные. Команда работает при отдельном выполнении через командную строку SSH.

Я использую эту команду:

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

Это код сценария оболочки, который создает файл ds_fbids.sqlи передает его в 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

Как правильно это сделать?

MUFC
источник

Ответы:

176

Вам нужно использовать -pфлаг для отправки пароля. И это сложно, потому что у вас не должно быть пробелов между -pи паролем.

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

Если вы используете пробел после -pтого, как он заставит клиент mysql интерактивно запрашивать пароль, а затем он интерпретирует следующий аргумент команды как имя базы данных:

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

На самом деле я предпочитаю хранить пользователя и пароль в ~ / .my.cnf, поэтому мне вообще не нужно помещать его в командную строку:

[client]
user = root
password = XXXXXXXX

Затем:

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

Re ваш комментарий:

Я все время запускаю команды mysql в пакетном режиме, подобные приведенным выше, в командной строке и в сценариях оболочки. Трудно диагностировать, что не так с вашим сценарием оболочки, потому что вы не предоставили точный сценарий или какие-либо сообщения об ошибках. Я предлагаю вам отредактировать исходный вопрос выше и привести примеры того, что идет не так.

Кроме того, когда я устраняю неполадки в сценарии оболочки, я использую -xфлаг, чтобы видеть, как он выполняет каждую команду:

$ bash -x myscript.sh
Билл Карвин
источник
Спасибо за быстрый ответ. Устал ставить пароль в самой командной строке. Настоящая проблема в том, что я помещаю эту команду в файл .sh, а затем выполняю этот сценарий оболочки. Команда в файле не выполняется в командной строке, но та же команда отлично работает, когда я выполняю только команду в командной строке.
MUFC
+ mysql -h dbservername -u user-name -ppassword dbname</br> : No such file or directoryids.sql</br> + $'\r' : command not found2:Это сообщение об ошибке, которое я получил
MUFC
Хорошо, тогда я бы сделал вывод, что ваш текущий рабочий каталог находится не там, где находится файл ids.sql. Также вы можете встроить в скрипт символы новой строки.
Билл Карвин
У меня есть новые строки, встроенные в мой сценарий оболочки после каждой команды. Все, что содержит мой сценарий оболочки, - это 3 команды командной строки, которые я не хочу запускать отдельно, поэтому я создал сценарий оболочки, чтобы они запускались без моего вмешательства, и я помещал новую строку после каждой команды. Это вызывает проблему?
MUFC
лучше избегать, -pесли пароль пустой или пустая строка, возможно, вы можете обновить свой пост? :)
Джеймс Оравек
118

Используйте этот синтаксис:

mysql -u $user -p$passsword -Bse "command1;command2;....;commandn"
Кшитидж Суд
источник
8
Я попал на эту страницу из Google, и это решение, которое я ожидал (соответствует заголовку вопроса).
Джанака Р. Раджапакша
16
Некоторые дополнительные сведения о параметрах из руководства: -B - для партии, печатать результаты, используя табуляцию в качестве разделителя столбцов, с каждой строкой на новой строке. С этой опцией mysql не использует файл истории. Пакетный режим приводит к нетабличному формату вывода и экранированию специальных символов. -s - это тихий режим. Производите меньше продукции. -e - выполнить инструкцию и выйти
wranvaud
Спасибо за вашу помощь! :)
haotang
Может ли он работать с heredoc?
zx1986
1
@ zx1986 Да и нет, HEREDOC. Зависит от того, как вы собираетесь его использовать. Использовать его для замены "command1;command2;....;commandn"части этого ответа не получится. Использование его для замены использования перенаправленного файла в синтаксисе OP может работать. Я рассмотрел эту проблему в своем ответе на этот вопрос.
Чиндраба
45

Все предыдущие ответы великолепны. Если вы хотите запустить простую однострочную команду sql, вы также можете использовать параметр -e.

mysql -h <host> -u<user> -p<password> database -e \
  "SELECT * FROM blah WHERE foo='bar';"
Jericon
источник
Мне нужно было сделать запрос в двойных ("") кавычках. Спасибо
user3132107
Я понимаю, и я так понимаю, вам действительно нужно поставить точку с запятой в конце запроса?
Лори,
19

Как выполнить сценарий SQL, используйте этот синтаксис:

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

Если вы используете host как localhost, вам не нужно об этом упоминать. Вы можете использовать это:

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

Это должно работать для Windows и Linux.

Если содержимое пароля содержит !(восклицательный знак), вы должны добавить \(обратную косую черту) перед ним.

Милинда Бандара
источник
1
Как указать базу данных? он должен быть внутри -e, например -e "use abc; source dbscript.sql"?
Abdul Muneer 05
9

На суть вопроса уже был дан ответ несколько раз, я просто подумал, что добавлю, что обратные кавычки имеют beaning как в сценариях оболочки, так и в SQL. Если вам нужно использовать их в SQL для указания имени таблицы или базы данных, вам нужно будет экранировать их в сценарии оболочки следующим образом:

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

Конечно, генерация SQL с помощью конкатенированного пользовательского ввода (переданные аргументы) не должна выполняться, если вы не доверяете пользовательскому вводу. Было бы намного безопаснее поместить его на другом языке сценариев с поддержкой параметров / правильным экранированием строк для вставки в MySQL.

Li1t
источник
5
mysql -h "hostname" -u usr_name -pPASSWD "db_name" < sql_script_file

( sql_script_fileпри необходимости используйте полный путь )

Если вы хотите перенаправить вывод в файл

mysql -h "hostname" -u usr_name -pPASSWD "db_name" < sql_script_file > out_file
виноградная лоза
источник
@Gus, в первую очередь спасибо за ценные комментарии. Для меня это сработало как обаяние. Я хочу, чтобы на выходе был файл Excel или .csv. как я могу этого добиться. Заранее спасибо.
Ash_and_Perl
@Ash_and_Perl Я только редактировал этот ответ, слава Vine, а не мне, это его ответ. Если у вас есть собственный вопрос, и вы уже пытались найти решение самостоятельно , я предлагаю вам создать вопрос. Таким образом вы сможете подробно описать, что вы пробовали и как это не удалось, и люди могут дать вам полный и исчерпывающий ответ (и получить за это баллы!).
Gus
5

Вы забыли -pили --password=(второе лучше читается):

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

(Кавычки не нужны, если вы уверены, что ваши учетные данные / имена не содержат пробелов или специальных символов оболочки.)

Обратите внимание, что на странице руководства также говорится, что предоставление учетных данных в командной строке небезопасно. Так что следуйте совету Билла о my.cnf.

Заостренные уши
источник
4

Как было сказано ранее, вы можете использовать -p для передачи пароля серверу.

Но я рекомендую это:

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

Обратите внимание, что пароля нет. Затем он запросит у вас пароль. Я бы ТОГДА ввел его. Чтобы ваш пароль не попал в историю командной строки сервера.

Это основная мера безопасности.

Если безопасность не вызывает беспокойства, я бы просто временно удалил пароль от пользователя базы данных. Потом после импорта - заново добавить.

Таким образом, любые другие учетные записи, которые могут иметь один и тот же пароль, не будут скомпрометированы.

Также кажется, что в вашем сценарии оболочки вы не ждете / не проверяете, действительно ли существует файл, который вы пытаетесь импортировать. Возможно, сценарий Perl еще не завершен.

Стерлинг Гамильтон
источник
1
Вы пропустили «автоматизированную» часть вопроса, и временное удаление пароля - действительно плохая идея.
PointedEars 08
Я прочитал это как «восстановить» и «автоматизировано», что означает «автоматизировано, но не навсегда». Но, как я уже сказал, «если безопасность не вызывает беспокойства». Я согласен - это ДЕЙСТВИТЕЛЬНО плохая идея.
Стерлинг Гамильтон
Прошу прощения, если я создал путаницу. Под автоматическим я имел в виду, что у меня есть два сценария perl, которые используются для создания файла .sql, но команда для сброса этого файла в БД не запускается сценарием оболочки, но она работает абсолютно файлово, если я запускаю эту команду в командной строке. Я хочу упростить выполнение этой команды в командной строке и запустить ее через сам сценарий оболочки.
MUFC
1
Vaibav: если бы вы могли поместить в свой вопрос фактический сценарий оболочки, возможно, я смогу вам помочь.
Стерлинг Гамильтон
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

использование

echo "your sql script;" | mysql -u -p -h db_name
senninha
источник
3

Чтобы «автоматизировать» процесс импорта сгенерированного .sqlфайла, избегая при этом всех ловушек, которые могут быть скрыты при попытке передать файлы, stdinи stdoutпросто скажите MySQL выполнить сгенерированный .sqlфайл с помощью SOURCEкоманды в MySQL.

Синтаксис краткого, но отличного ответа от Кшитиджа Суда дает лучшую отправную точку. Короче говоря, измените команду OP в соответствии с синтаксисом Кшитиджа Суда и замените команды в нем на SOURCEкоманду:

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

Если имя базы данных включено в сгенерированный .sqlфайл, его можно исключить из команды.

Здесь предполагается, что сгенерированный файл действителен как .sqlфайл сам по себе. Поскольку файл не перенаправляется, не передается по конвейеру или не обрабатывается оболочкой каким-либо другим образом, нет проблем с необходимостью экранирования любого из символов в сгенерированном выводе из-за оболочки. Правила относительно того, что нужно экранировать в .sqlфайле, конечно, по-прежнему применяются.

Как решить проблемы безопасности, связанные с паролем в командной строке, или в my.cnfфайле, и т. Д., Было хорошо рассмотрено в других ответах с некоторыми отличными предложениями. Мой любимый ответ , от Дэнни , обложки , которые, в том числе , как справиться с проблемой при работе с cronработы, или что - нибудь еще.


Чтобы ответить на комментарий (вопрос?) К краткому ответу, который я упомянул: Нет, его нельзя использовать с синтаксисом HEREDOC, поскольку указана эта команда оболочки. HEREDOC можно использовать в синтаксисе версии перенаправления (без -Bseопции), поскольку перенаправление ввода-вывода - это то, на чем построен HEREDOC. Если вам нужна функциональность HEREDOC, было бы лучше использовать ее при создании .sqlфайла, даже если он временный, и использовать этот файл в качестве «команды» для выполнения с помощью командной строки 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

Имейте в виду, что из-за расширения оболочки вы можете использовать переменные оболочки и среды в HEREDOC. Обратной стороной является то, что вы должны избегать каждой обратной кавычки. MySQL использует их в качестве разделителей для идентификаторов, но оболочка, которая первой получает строку, использует их в качестве разделителей исполняемых команд. Пропустите escape-код по одной обратной кавычке в команде MySQL, и все это взорвется ошибками. Всю проблему можно решить, используя указанную в кавычках LimitString для 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

Удаление расширения оболочки таким образом устраняет необходимость экранировать обратные кавычки и другие специальные символы оболочки. Он также удаляет возможность использовать в нем переменные оболочки и среды. Это в значительной степени устраняет преимущества использования HEREDOC внутри сценария оболочки для начала.

Другой вариант - использовать строки в многострочных кавычках, разрешенные в Bash, с версией синтаксиса пакета (с -Bse). Я не знаю других оболочек, поэтому не могу сказать, работают ли они и в них. В любом случае вам нужно будет использовать это для выполнения более чем одного .sqlфайла с SOURCEкомандой, поскольку это не завершается a, ;как другие команды MySQL, и только один разрешен на строку. Многострочная строка может быть заключена в одинарные или двойные кавычки с обычным эффектом расширения оболочки. Здесь также есть те же предостережения, что и при использовании синтаксиса HEREDOC для обратных кавычек и т. Д.

Потенциально лучшим решением было бы использовать язык сценариев, Perl, Python и т. Д., Для создания .sqlфайла, как это сделал OP, и SOURCEэтот файл с использованием простого командного синтаксиса вверху. Языки сценариев намного лучше справляются со строками, чем оболочка, и большинство из них имеют встроенные процедуры для обработки кавычек и экранирования, необходимых при работе с MySQL.

Chindraba
источник
2

Важным соображением для доступа к mysql из сценария оболочки, используемого в cron, является то, что mysql смотрит на зарегистрированного пользователя, чтобы определить .my.cnf для загрузки.

Это не работает с cron. Это также может сбивать с толку, если вы используете su / sudo, поскольку зарегистрированный пользователь может не быть пользователем, от имени которого вы работаете.

Я использую что-то вроде:

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

Просто убедитесь, что права собственности и права доступа пользователей и групп установлены правильно и строго в файле .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

Как мне выполнить командную строку с безопасным паролем ?? используйте редактор конфига !!!

Начиная с mysql 5.6.6, вы можете сохранить пароль в файле конфигурации, а затем выполнять такие команды cli ....

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

--login-path заменяет переменные ... хост, пользователь И пароль. отличное право!

Artistan
источник
0

Я написал сценарий оболочки, который будет читать данные из файла свойств, а затем запускать сценарий mysql в сценарии оболочки. обмен этим может помочь другим.

#!/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
источник