Подавлять предупреждающие сообщения, используя mysql из терминала, но пароль написан в скрипте bash

273

Когда я попытался запустить следующую команду на MySQL из терминала:

mysql -u $user -p$password -e "statement"

Выполнение работает как положено, но всегда выдает предупреждение:

Предупреждение. Использование пароля в интерфейсе командной строки может быть небезопасным.

Тем не менее, я должен выполнить вышеупомянутое утверждение, используя переменную окружения ( $password), в которой хранится мой пароль, потому что я хочу выполнить команду итеративно в скрипте bash из терминала, и мне определенно не нравится идея ожидания появления подсказки и заставляет меня вводить пароль 50 или 100 раз в одном скрипте. Итак, вот мой вопрос:

  • Возможно ли подавить предупреждение? Команда работает правильно, как я уже говорил, но окно становится довольно грязным, когда я повторяю цикл и запускаю команду 50 или 100 раз.

  • Должен ли я подчиниться предупреждающему сообщению и НЕ записывать свой пароль в свой сценарий? Если это так, то должен ли я вводить свой пароль каждый раз, когда приглашение заставляет меня сделать это?

Бег man mysqlне помогает, говоря только

--show-warnings
Приводит к выводу предупреждений после каждого оператора, если они есть. Этот параметр применяется к интерактивному и пакетному режимам.

и ничего не упоминает о том, как отключить функционал, если я что-то не упустил.

Я на OS X 10.9.1 Mavericks и использую MySQL 5.6 от homebrew.

Blaszard
источник
14
Рекомендуемый способ сохранить пароль в файле опций (как л [client] password=my_passwordв ~/.my.cnf). Конечно, это также имеет некоторые последствия для безопасности, но, по крайней мере, оно не доступно для всех, кто может работать ps, и вы можете управлять им с помощью прав доступа к файлам.
Антон Коваленко
4
mysql -u root password root -e "statement" > /dev/null?
О, кстати, вы также можете использовать что-то вроде Python pexcept. Он может выполнять терминальные вставки, а также обрабатывать обратную связь, которую дает команда. Таким образом, вы можете просто пропустить этот подробный вывод и
6
Рекомендуемый способ ИМО наказывает тех, кто делает правильные вещи, чтобы защитить тех, кто делает неправильные вещи. Если пароль хранится в файле скрипта, он не будет отображаться с ps или в любом журнале. Это правильный способ сделать это. Помещение файла во внешний файл помогает тем, кто взломает пароль, но с этого плохо начинать. Тем временем скрипты, которые выполнялись годами, теперь терпят неудачу, и мы должны изменить их только потому, что это предупреждение появляется в stderr.
Нестор Уркиса
2
Для рекомендуемого метода, который не хранит пароль в открытом виде, подробно описано в dev.mysql.com/doc/refman/5.6/en/mysql-config-editor.html
Энтони

Ответы:

250

Если ваша клиент-серверная версия MySQL 5.6.xa, чтобы избежать сообщения ПРЕДУПРЕЖДЕНИЕ, используйте инструменты mysql_config_editor :

mysql_config_editor set --login-path=local --host=localhost --user=username --password

Затем вы можете использовать в своем сценарии оболочки:

mysql --login-path=local  -e "statement"

Вместо того:

mysql -u username -p pass -e "statement"
Кристиан Порта
источник
28
Помните, что --login-pathдолжен предшествовать всем остальным аргументам. Я пытался mysqldump --tables --login-path=localи получил ошибку unknown variable 'login-path=local'.
Тулио
Клиент командной строки mysql по умолчанию будет искать путь входа «client». Вы можете упростить инструкции до "mysql -e 'Statement'", внеся небольшое изменение.
Морган Токер
2
Это работает нормально, если мы напрямую выполняем файл оболочки, но не работает, если
Набиэль Аршад
1
@NabeelArshad Я думаю, что это потому, что в вашем crontab «дом» для пользователя не установлен (ENV vars в целом), поэтому в crontab клиент не может найти правильный ~ / .mylogin.cnf
Cristian Porta
1
@NamGVU, я не уверен, однако, я считаю, что это решение хранит зашифрованные пароли.
Жекаус
209

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

mysql --defaults-extra-file=/path/to/config.cnf

или

mysqldump --defaults-extra-file=/path/to/config.cnf 

Где config.cnf содержит:

[client]
user = whatever
password = whatever
host = whatever

Это позволяет вам иметь несколько конфигурационных файлов - для разных серверов / ролей / баз данных. Использование ~ / .my.cnf позволит вам иметь только один набор конфигурации (хотя это может быть полезным набором значений по умолчанию).

Если вы работаете в дистрибутиве на основе Debian и работаете от имени пользователя root, вы можете пропустить вышеупомянутое и просто использовать /etc/mysql/debian.cnf, чтобы войти ...:

mysql --defaults-extra-file=/etc/mysql/debian.cnf

Дэвид Гудвин
источник
12
Примечание: --defaults-extra-fileдолжен быть первым вариантом, в противном случае mysql жалуется mysqldump: unknown variable 'defaults-extra-file.
pevik
4
Потрясающая альтернатива принятому ответу. Определенно не устанавливайте MYSQL_PWDпеременную ....
DudeOnRock
1
Определенно хороший вариант для версий ниже 5.6. В противном случае я бы пошел с принятым ответом.
dkniffin
21
Альтернатива сделать временный .cnf файла должны сделать это в Bash: mysql --defaults-extra-file=<(printf "[client]\nuser = %s\npassword = %s" "$user" "$pwd") -e "statement". Поскольку printfBash выполняется непосредственно, он не отображается в ps.
Дейв Джеймс Миллер
3
Мне нужно было использовать, --defaults-fileа не --defaults-extra-file, потому что последний отдает предпочтение настройкам в ~ / .my.cnf.
Роджер Дуек
186

Один из методов, который удобен (но в равной степени небезопасен), заключается в использовании:

MYSQL_PWD=xxxxxxxx mysql -u root -e "statement"

Обратите внимание, что официальные документы рекомендуют против этого.
См. 6.1.2.1 Руководство для конечного пользователя по защите паролем (Mysql Manual для версии 5.6) :

Хранение вашего пароля в MYSQL_PWDпеременной окружения

Этот метод указания вашего пароля MySQL должен считаться крайне небезопасным и не должен использоваться. Некоторые версии ps включают опцию для отображения среды запущенных процессов. В некоторых системах, если вы установили MYSQL_PWD, ваш пароль доступен любому другому пользователю, который запускает ps . Даже в системах без такой версии ps неразумно предполагать, что нет других методов, с помощью которых пользователи могут исследовать среды процессов.

Иван Доков
источник
6
Это не работает в моей Баш скрипт:Access denied for user 'root'@'localhost' (using password: NO)
rubo77
24
В сценарии вам нужно export MYSQL_PWD=whatever .
Бунт
2
Поскольку мой запрос очень быстрый, я выбрал эту опцию. Затем я установил что-то поддельное после выполнения запроса.
TimH - Codidact
11
В сценарии вам не нужно запускать export, просто поместите все в одну строку:MYSQL_PWD=xxxxxxxx mysql -u root -e "statement"
JD
1
@JD: у меня работает в Ubuntu 16.04 с MySQL 5.7.21.
мивк
70

Если вы хотите использовать пароль в командной строке, я обнаружил, что это работает для фильтрации конкретного сообщения об ошибке:

mysqlcommand 2>&1 | grep -v "Warning: Using a password"

Это в основном перенаправление стандартной ошибки на стандартный вывод - и использование grep для удаления всех строк, которые соответствуют «Предупреждение. Использование пароля».

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

johnmontfx
источник
Это отличное решение для использования в задачах с одной строкой, которые называются другими задачами, такими как создание задачи Rake для развертывания Capistrano.
JakeGould
2
Отлично и просто отключить это сообщение, не нужно ничего трогать в настройке MySQL.
ajaaskel
Как бы я использовал это с mysqldump, где у меня уже есть перенаправление для SQL?
MacroMan
1
Это действительно плохое решение по сравнению с другими здесь. Может произойти сбой с любой последующей версией MySQL, если текст поменяется, может не работать и в другой локали.
yktoo,
42

Вот как я получил мой bash-скрипт для ежедневного резервного копирования базы данных mysqldump для более безопасной работы. Это расширение великого ответа Кристиана Порта.

  1. Сначала используйте mysql_config_editor (поставляется с mysql 5.6+) для настройки зашифрованного файла паролей. Предположим, ваше имя пользователя "db_user". Запуск из командной строки:

    mysql_config_editor set --login-path=local --host=localhost --user=db_user --password

    Он запрашивает пароль. После того, как вы введете его, пользователь / пароль сохранятся в зашифрованном виде в вашемhome/system_username/.mylogin.cnf

    Конечно, измените «system_username» на ваше имя пользователя на сервере.

  2. Измените ваш bash скрипт из этого:

    mysqldump -u db_user -pInsecurePassword my_database | gzip > db_backup.tar.gz

    к этому:

    mysqldump --login-path=local my_database | gzip > db_backup.tar.gz

Нет больше открытых паролей.

Баттл Буткус
источник
10

Самый простой способ

mysql -u root -pMYPASSWORD -e "show databases" 2>/dev/null
JavaGuy
источник
43
Проблема в том, что это также подавит допустимые ошибки в вашем скрипте.
man910
4
Также вы можете создать файл журнала 2> /var/log/myscript.log для регистрации этих ошибок.
Скамасле
1
использовать 2>/dev/null | grep -v "mysql: [Warning] Using a password on the command line interface can be insecure."для подавления только рассматриваемого предупреждения
Hafenkranich
10

Вы также можете запустить mysql_config_editor в своем скрипте, чтобы передать пароль при указании пути входа

expect -c "
spawn mysql_config_editor set --login-path=$mySqlUser --host=localhost --user=$mySqlUser --password
expect -nocase \"Enter password:\" {send \"$mySqlPassword\r\"; interact}
"

Это запускает ожидаемый сеанс, который можно использовать в сценариях для взаимодействия с подсказками.

Смотрите этот пост

phylanx
источник
Это «>» действительно должно быть там?
Дэвид Гудвин
yes '>' должен быть там, чтобы mysql_config_editor получал информацию от stdout. То, что передается из stdout в mysql_config_editor, это пароль, который вы хотите, чтобы этот пользователь имел без '>', тогда происходит то, что команда echo анализируется, и все, что вы увидите, это все после команды echo
phylanx
Итак, вы имеете в виду использовать оператор трубы "|", верно? По крайней мере, в * nix и DOS «>» захватит STDOUT и запишет его в файл с именем «mysql_config_editor» в текущем рабочем каталоге.
Джей Дансанд
Да, вы правы, я отредактировал свой оригинальный ответ
phylanx
7

хорошо, решение без временных файлов или чего-либо:

mysql --defaults-extra-file=<(echo $'[client]\npassword='"$password") -u $user -e "statement"

это похоже на то, что упоминали другие, но здесь вам не нужен фактический файл, эта часть команды подделывает файл: <(echo ...) (обратите внимание, что в середине нет места<(

Сантьяго Аристи
источник
это не сработает, если у вас уже есть .my.cnfфайл ~/.с паролем
santiago arizti
5
shell> mysql_config_editor set --login-path=local
     --host=localhost --user=localuser --password
Enter password: enter password "localpass" here
shell> mysql_config_editor set --login-path=remote
     --host=remote.example.com --user=remoteuser --password
Enter password: enter password "remotepass" here

Чтобы увидеть, что mysql_config_editor записал в файл .mylogin.cnf, используйте команду print:

shell> mysql_config_editor print --all
[local]
user = localuser
password = *****
host = localhost
[remote]
user = remoteuser
password = *****
host = remote.example.com

Команда print отображает каждый путь входа в систему в виде набора строк, начинающихся с заголовка группы, указывающего имя пути входа в квадратных скобках, за которым следуют значения параметров для пути входа в систему. Значения пароля маскируются и не отображаются в виде открытого текста.

Как показано в предыдущих примерах, файл .mylogin.cnf может содержать несколько путей входа в систему. Таким образом, mysql_config_editor позволяет легко настроить несколько «личностей» для подключения к различным серверам MySQL. Любой из них можно будет выбрать по имени позже, используя опцию --login-path, когда вы вызываете клиентскую программу. Например, чтобы подключиться к локальному серверу, используйте эту команду:

shell> mysql --login-path=local

Чтобы подключиться к удаленному серверу, используйте эту команду:

shell> mysql --login-path=remote
Бета
источник
Что если я хочу выполнить команду mysqldump от имени пользователя www-data? www-data не имеет домашнего каталога ... как мне настроить mysql_config_editor для пользователя www-data?
lewis4u
5

С https://gist.github.com/nestoru/4f684f206c399894952d

# Let us consider the following typical mysql backup script:
mysqldump --routines --no-data -h $mysqlHost -P $mysqlPort -u $mysqlUser -p$mysqlPassword $database

# It succeeds but stderr will get:
# Warning: Using a password on the command line interface can be insecure.
# You can fix this with the below hack:
credentialsFile=/mysql-credentials.cnf
echo "[client]" > $credentialsFile
echo "user=$mysqlUser" >> $credentialsFile
echo "password=$mysqlPassword" >> $credentialsFile
echo "host=$mysqlHost" >> $credentialsFile
mysqldump --defaults-extra-file=$credentialsFile --routines --no-data $database

# This should not be IMO an error. It is just a 'considered best practice'
# Read more from http://thinkinginsoftware.blogspot.com/2015/10/solution-for-mysql-warning-using.html
Нестор Уркиса
источник
3

Другой альтернативой является использование sshpass для вызова mysql, например:

sshpass -p topsecret mysql -u root -p username -e 'statement'
lewiz
источник
Кажется, работает, но вы должны удалить имя пользователя из командной строки, не так ли?
e2-e4
3

Простой трудоемкий скрипт. Назовите этот «mysql» и поместите его на вашем пути перед «/ usr / bin». Очевидные варианты для других команд, или, если текст предупреждения отличается.

#!/bin/sh

(
(
(
(
(
    /usr/bin/mysql "$@"
) 1>&9 
) 2>&1
) | fgrep -v 'mysql: [Warning] Using a password on the command line interface can be insecure.'
) 1>&2 
) 9>&1
Дэвид Г.
источник
3
Хотя этот ответ немного запутанный, я просто проголосовал за него, потому что мне так страшно видеть ответы, которые не являются явно неправильными или являются немного нетрадиционными, получая отрицательные отзывы без комментариев! Неудивительно, что Дэвид не ответил ни на какие другие вопросы! Он запрыгнул внутрь и попытался помочь с новым решением, и ему без объяснения причин ударили! ФУ анонимных пижонов, которые не оставляют комментариев!
Джереми Дэвис
3
+1 согласен Джереми Дэвис. Это запутанно, но если оставить без другого варианта, это может быть приемлемым. Это определенно не так, в отличие от отключения предупреждений, которое должно быть самой глупой идеей!
Бен Макинтайр,
1
@JeremyDavis Да, это было запутанно, главным образом потому, что я хотел показать работу. Это могло бы быть сделано без каких-либо скобок, но, возможно, было менее ясно. Это было также мое первое не читающее занятие во всем обмене стека ... после которого я долгое время не трогал его. Ваш комментарий был определенно оценен.
Дэвид Дж.
@DavidG. - Рад, что мой комментарий был ценным для вас. Также приятно видеть, что вы вернулись и что ваш ответ сейчас на положительной территории. Лично я не думаю, что голосование без комментирования должно быть разрешено ... Как кто-то должен учиться, когда его критикуют за то, что он ушел ?!
Джереми Дэвис
Сказав это, пересматривая ваш ответ, я не уверен, что наилучшее решение - это постоянное решение (по сути, завершение mysql) временной проблемы (подавление сообщения об ошибке для использования в одном скрипте). IMO-обертывание mysql в функцию внутри скрипта (здесь будет хорошо использовать ваш метод) - превосходный подход. Мой 2c ... :)
Джереми Дэвис
3

Вот решение для Docker в сценарии / bin / sh:

docker exec [MYSQL_CONTAINER_NAME] sh -c 'exec echo "[клиент]"> /root/mysql-credentials.cnf'

docker exec [MYSQL_CONTAINER_NAME] sh -c 'exec echo "user = root" >> /root/mysql-credentials.cnf'

docker exec [MYSQL_CONTAINER_NAME] sh -c 'exec echo "password = $ MYSQL_ROOT_PASSWORD" >> /root/mysql-credentials.cnf'

docker exec [MYSQL_CONTAINER_NAME] sh -c 'exec mysqldump --defaults-extra-file = / root / mysql-credentials.cnf --all-database'

Замените [MYSQL_CONTAINER_NAME] и убедитесь, что в вашем контейнере установлена ​​переменная среды MYSQL_ROOT_PASSWORD.

Надеюсь, это поможет вам, как это может помочь мне!

pcmanprogrammeur
источник
Неплохо. Я только что использовал один вызов с возвратом, например, при docker exec [MYSQL_CONTAINER_NAME] sh -c 'exec echo "[client] [RETURN HERE] password=pa55" > /root/defaults'использовании --defaults-fileон тоже забирает root.
Мэтью Уилкоксон
3

Вы также можете просто перенаправить стандартный вывод ошибки STDERR в / dev / null

Так что просто сделайте:

mysql -u $user -p$password -e "statement" 2> /dev/null

Джозеф Ши
источник
7
Я бы
отказался
1

Лично я использую скрипт-обертку, чтобы поймать эту ошибку. Вот пример кода:

#!/bin/bash

#echo $@ | cat >> /home/mysqldump.log 2>/dev/null
ERR_FILE=/tmp/tmp_mdump.err

# Execute dumper
/usr/bin/mysqldump $@ 2>$ERR_FILE

# Determine error and remove tmp file
ERROR=`cat $ERR_FILE`
rm $ERR_FILE

# Handle an error
if [ "" != "$ERROR" ]; then

        # Error occured
        if [ "Warning: Using a password on the command line interface can be insecure." != "$ERROR" ]; then
                echo $ERROR >&2
                exit 1
        fi
fi
И
источник
1

Для PowerShell ( pwshне bash), это было решение rube-goldberg ... Моей первой попыткой было обернуть вызовы mysqlвtry/catch функцию, но из-за некоторого странного поведения в обработке ошибок PowerShell это было нежизнеспособным.

Решение состояло в том, чтобы переопределить $ErrorActionPreferenceтолько достаточно долго, чтобы объединить и захватить STDERRи STDOUTи проанализировать слово ERRORи перебросить по мере необходимости. Причина, по которой мы не смогли поймать и выпустить, "^mysql.*Warning.*password"заключается в том, что PowerShell обрабатывает и выдает ошибку как один поток, поэтому вы должны захватить ее все для фильтрации и повторного выброса. : /

Function CallMySQL() {
    # Cache the error action preference
    $_temp = $ErrorActionPreference
    $ErrorActionPreference = "Continue"

    # Capture all output from mysql
    $output = (&mysql --user=foo --password=bar 2>&1)

    # Restore the error action preference
    $ErrorActionPreference = $_temp

    if ($output -match "ERROR") {
        throw $output
    } elseif($output) {
        "   Swallowing $output"
    } else {
        "   No output"
    }
}

Примечание: PowerShell доступен для Unix, поэтому данное решение является кроссплатформенным. Это может быть адаптировано bashс некоторыми незначительными изменениями синтаксиса.

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

Было бы неплохо, если бы mysqlпросто добавили опцию подавления этого предупреждения.

tresf
источник
1

Если вам случится использовать Rundeck для планирования ваших задач или любую другую платформу, где вы запрашиваете mylogin.cnfфайл, я успешно использовал следующий код оболочки, чтобы указать новое местоположение файла перед продолжением вызовов sql:

if test -f "$CUSTOM_MY_LOGINS_FILE_PATH"; then
   chmod 600 $CUSTOM_MY_LOGINS_FILE_PATH
   export MYSQL_TEST_LOGIN_FILE="$CUSTOM_MY_LOGINS_FILE_PATH"
fi

...

result=$(mysql --login-path=production -NBA -D $schema -e "$query")

Где MYSQL_TEST_LOGIN_FILEпеременная окружения, для которой можно задать путь к файлу, отличному от пути по умолчанию.

Это особенно полезно, если вы работаете в разветвленном процессе и не можете перемещать или копировать файлы в $HOMEкаталог.

Смотрите документацию здесь.

Patrick.SE
источник
0

Лучшее решение - использовать псевдоним:

alias [yourapp]-mysql="mysql -u root -psomepassword -P3306 -h 127.0.0.1"

Например, поместите это в ваш скрипт:

alias drupal-mysql="mysql -u root -psomepassword -P3306 -h 127.0.0.1"

затем в вашем скрипте для загрузки базы данных:

drupal-mysql database_name < database_dump.sql

запустить заявление:

drupal-mysql -e "EXEC SOMESTATEMENT;"
Нил Дэвис
источник
затем uniaias псевдонимы:
Нил Дэвис
Кстати, вы не можете использовать псевдоним, если вы вызываете mysql внутри функции внутри скрипта.
user3616725
0

Определите помощника:

remove-warning () {
    grep -v 'mysql: [Warning] Using a password on the command line interface can be insecure.'
}

Используй это:

mysql -u $user -p$password -e "statement" 2>&1 | remove-warning

Tachaan! Ваш код чистый и приятный для чтения

(проверено с помощью bash)

volingas
источник
-1

Другое решение (например, из скрипта):

 sed -i'' -e "s/password=.*\$/password=$pass/g" ~/.my.cnf
 mysql -h $host -u $user $db_name -e "$sql_cmd"

-i''Вариант здесь для совместимости с Mac OS X. Стандартные UNIX операционки можно использовать прямой-i

Бенуа Даффез
источник
1
пароль все еще находится в командной строке 'sed', поэтому он остается видимым в списках процессов, даже если ненадолго.
Энтони
-1

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

Это не элегантно, но в доке env это действительно не имеет значения. В основном все, что это делает, это игнорирует вывод, который находится не в последней строке. Вы можете сделать то же самое с awk, и изменить, чтобы вернуть все, кроме первой строки и т. Д.

Это возвращает только последнюю строку

mysql -u db_user -pInsecurePassword my_database ... | sed -e '$!d'

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

WiR3D
источник
-1

Самый простой способ:

mysql -u root -p YOUR_DATABASE

Введите это, и вам нужно будет ввести свой пароль.

Примечание: Да, без точки с запятой.

LukasNiessen
источник
-3

Вы можете выполнить mySQL и подавить предупреждения и сообщения об ошибках, используя / dev / null, например:

# if you run just a SQL-command
mysql -u ${USERNAME} -p${PASSWORD} -h ${HOST} ${DATABASE} -e "${STATEMENT}" &> /dev/null

# Or you can run SQL-script as a file
mysql -u ${USERNAME} -p${PASSWORD} -h ${HOST} ${DATABASE} < ${FILEPATH} &> /dev/null

Куда:

${USERNAME} - existing mysql user

${PASSWORD} - password

${HOST}     - ip or hostname, for example 'localhost'

${DATABASE} - name of database

${STATEMENT}- SQL command

${FILEPATH} - Path to the SQL-script

наслаждаться!

Стан Халипа
источник
1
Просто имейте в виду, что он подавит ВСЕ сообщения об ошибках, а не только предупреждения о пароле.
Саймон Ист
-3

Это сработало для меня - только что добавлено 2> nullпосле $(mysql_command), и будет подавлять только сообщения об ошибках и предупреждениях.

ММГ
источник
1
Это также означает, что вы не получите отчет, когда что-то пойдет не так!
Энтони
Кроме того, вы, вероятно, хотели 2>/dev/null. Использование 2> nullпросто поместит вывод в файл с именем «null» в текущем каталоге.
Thelogix