Suprimir mensagens de aviso usando o mysql do Terminal, mas a senha escrita no script bash

273

Quando tentei executar o seguinte comando no MySQL a partir do Terminal:

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

A execução funciona conforme o esperado, mas sempre emite um aviso:

Aviso: O uso de uma senha na interface da linha de comandos pode ser inseguro.

No entanto, tenho que conduzir a declaração acima usando uma variável de ambiente ( $password) que armazena minha senha, porque desejo executar o comando iterativamente no script bash a partir do Terminal e, definitivamente, não gosto da ideia de esperar um prompt aparecer e me forçando a inserir minha senha 50 ou 100 vezes em um único script. Então aqui está a minha pergunta:

  • É possível suprimir o aviso? O comando funciona corretamente como afirmei, mas a janela fica bastante bagunçada quando faço um loop e executo o comando 50 ou 100 vezes.

  • Devo obedecer à mensagem de aviso e NÃO escrevo minha senha no meu script? Se for esse o caso, tenho que digitar minha senha toda vez que o prompt me obriga a fazer isso?

Correr man mysqlnão ajuda, dizendo apenas

--show-warnings
Faça com que os avisos sejam mostrados após cada instrução, se houver algum. Esta opção se aplica ao modo interativo e em lote.

e não menciona nada sobre como desativar a funcionalidade, se não estiver faltando alguma coisa.

Estou no OS X 10.9.1 Mavericks e uso o MySQL 5.6 do homebrew.

Blaszard
fonte
14
A maneira recomendada é armazenar sua senha em um arquivo de opções (como [client] password=my_passwordem ~/.my.cnf). Certamente ele tem algumas implicações de segurança também, mas pelo menos não é acessível a qualquer um que pode executar ps, e você tem controle sobre ele com permissões de arquivo.
Anton Kovalenko
4
mysql -u root password root -e "statement" > /dev/null?
Ah, a propósito, você também pode usar algo como Python pexcept. Ele pode fazer inserções de terminal e também lidar com o feedback que o comando fornece. Desta forma, você pode simplesmente ignorar que a saída detalhada e tira da saída real que você quer :)
6
A maneira recomendada pela IMO penaliza aqueles que fazem a coisa certa para proteger aqueles que fazem a coisa errada. Se a senha for armazenada dentro de um arquivo de script, ela não aparecerá com ps ou em qualquer log. Essa é a maneira correta de fazer isso. Colocar o arquivo em um arquivo externo ajuda aqueles que agendariam a senha, mas que é ruim para começar. Enquanto isso, os scripts em execução há anos falham e precisamos modificá-los apenas porque esse aviso aparece no stderr.
Nestor Urquiza
2
Para o método recomendado, o whcih não armazena a senha de forma clara, está detalhado em dev.mysql.com/doc/refman/5.6/en/mysql-config-editor.html
Anthony

Respostas:

250

Se a sua versão cliente / servidor do MySQL é uma maneira 5.6.xa de evitar que a mensagem WARNING esteja usando as ferramentas mysql_config_editor :

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

Então você pode usar no seu shell script:

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

Ao invés de:

mysql -u username -p pass -e "statement"
Cristian Porta
fonte
28
Lembre-se de que isso --login-pathtem que vir antes de todos os outros argumentos. Eu estava tentando mysqldump --tables --login-path=locale recebendo o erro unknown variable 'login-path=local'.
Tulio
O cliente de linha de comando do mysql procurará no caminho de login do 'cliente' por padrão. Você pode simplificar as instruções para "mysql -e 'statement'" fazendo uma pequena alteração.
Morgan Tocker
2
Isso é bom trabalhar se executar diretamente o arquivo de shell, mas não funciona se for chamado a partir crontab
Nabeel Arshad
1
@NabeelArshad Acho que isso ocorre porque no seu crontab a "casa" para o usuário não está definida (Vars ENV em geral), portanto, no crontab, o cliente não consegue encontrar o ~ / .mylogin.cnf correto
Cristian Porta
1
@ NamGVU, não tenho certeza, no entanto, acredito que esta solução armazene senhas criptografadas.
Zhekaus
209

Eu uso algo como:

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

ou

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

Onde config.cnf contém:

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

Isso permite que você tenha vários arquivos de configuração - para diferentes servidores / funções / bancos de dados. Usar ~ / .my.cnf permitirá apenas que você tenha um conjunto de configurações (embora possa ser um conjunto útil de padrões).

Se você está em uma distro baseada no Debian e está executando como root, pode pular o acima e usar /etc/mysql/debian.cnf para entrar ...:

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

David Goodwin
fonte
12
Nota: --defaults-extra-filedeve ser a primeira opção, caso contrário o mysql atenderá mysqldump: unknown variable 'defaults-extra-file.
pevik
4
Alternativa impressionante para a resposta aceita. Definitivamente não definir a MYSQL_PWDvariável ....
DudeOnRock
1
Definitivamente, uma boa opção para versões abaixo de 5.6. Caso contrário, eu iria com a resposta aceita.
dkniffin
21
Uma alternativa para fazer uma ficheiro.cnf temporária é fazer isso em Bash: mysql --defaults-extra-file=<(printf "[client]\nuser = %s\npassword = %s" "$user" "$pwd") -e "statement". Como o printfBash é executado diretamente, ele não aparece ps.
Dave James Miller
3
Eu precisava usar, em --defaults-filevez de --defaults-extra-file, porque o último deu preferência às configurações em ~ / .my.cnf.
Roger Dueck
186

Um método que é conveniente (mas igualmente inseguro) é usar:

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

Observe que os documentos oficiais recomendam isso.
Veja 6.1.2.1 Diretrizes do Usuário Final para Segurança de Senha (Manual Mysql para Versão 5.6) :

Armazenando sua senha na MYSQL_PWDvariável de ambiente

Este método de especificar sua senha do MySQL deve ser considerado extremamente inseguro e não deve ser usado. Algumas versões do ps incluem uma opção para exibir o ambiente dos processos em execução. Em alguns sistemas, se você definir MYSQL_PWD, sua senha será exposta a qualquer outro usuário que execute ps . Mesmo em sistemas sem essa versão do ps , não é aconselhável supor que não existem outros métodos pelos quais os usuários possam examinar os ambientes de processos.

Ivan Dokov
fonte
6
Isso não funciona no meu script bash:Access denied for user 'root'@'localhost' (using password: NO)
rubo77 5/15
24
Em um script, você precisa export MYSQL_PWD=whatever.
Riot
2
Como minha consulta é muito rápida, optei por esta opção. Depois, defino-o como algo falso depois de executar a consulta.
TimH - Codidact
11
Em um script que você não precisa executar export, basta colocar tudo em uma linha:MYSQL_PWD=xxxxxxxx mysql -u root -e "statement"
JD
1
@JD: funciona para mim no Ubuntu 16.04 com o MySQL 5.7.21.
precisa saber é
70

Se você deseja usar uma senha na linha de comando, descobri que isso funciona para filtrar a mensagem de erro específica:

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

É basicamente redirecionar o erro padrão para a saída padrão - e usar grep para descartar todas as linhas que correspondem a "Aviso: Usando uma senha".

Dessa forma, você pode ver qualquer outra saída, incluindo erros. Eu uso isso para vários scripts de shell, etc.

johnmontfx
fonte
Esta é uma excelente solução para uso em tarefas de uma linha chamadas em outras tarefas, como a criação de uma tarefa Rake para uma implantação do Capistrano.
JakeGould
2
Excelente e simples para silenciar essa mensagem, não é necessário tocar em nada na configuração do MySQL.
ajaaskel
Como eu usaria isso com o mysqldump, onde já tenho um redirecionamento para o SQL?
MacroMan
1
Esta é uma solução muito ruim em comparação com as outras aqui. Pode falhar com qualquer versão subsequente do MySQL, caso o texto mude, também pode não funcionar em outro código do idioma.
yktoo 24/09
42

Aqui está como obtive meu script bash para meus backups diários do banco de dados mysqldump para trabalhar com mais segurança. Esta é uma expansão da grande resposta de Cristian Porta.

  1. Primeiro, use mysql_config_editor (fornecido com o mysql 5.6+) para configurar o arquivo de senha criptografada. Suponha que seu nome de usuário seja "db_user". Executando a partir do prompt do shell:

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

    Solicita a senha. Depois de inseri-lo, o usuário / passe é salvo criptografado em seuhome/system_username/.mylogin.cnf

    Claro, mude "system_username" para o seu nome de usuário no servidor.

  2. Mude seu script bash para isso:

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

    para isso:

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

Não há mais senhas expostas.

Buttle Butkus
fonte
10

A maneira mais fácil é

mysql -u root -pMYPASSWORD -e "show databases" 2>/dev/null
JavaGuy
fonte
43
O problema é que isso também suprimirá erros legítimos em seu script.
precisa saber é o seguinte
4
Além disso, você pode criar um arquivo de log 2> /var/log/myscript.log para registrar esses erros.
Skamasle
1
usar 2>/dev/null | grep -v "mysql: [Warning] Using a password on the command line interface can be insecure."para suprimir apenas o aviso em questão
Hafenkranich
10

Você também pode executar o mysql_config_editor no seu script para passar a senha ao especificar o caminho de login

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

Isso inicia uma sessão de espera que pode ser usada em scripts para interagir com prompts

Veja este post

phylanx
fonte
Será que '>' realmente deveria estar lá?
David Goodwin
yes '>' deve estar lá para que o mysql_config_editor receba a entrada do stdout. O que está sendo passada de stdout para mysql_config_editor é a senha que você deseja que este usuário tenha Sem o '>' então o que acontece é que o comando echo é analisado e tudo o que você vê é tudo após o comando echo
phylanx
Então, você quer usar o operador de tubo "|", certo? Pelo menos, no * nix e no DOS, ">" capturará o STDOUT e o gravará em um arquivo chamado "mysql_config_editor" no diretório de trabalho atual.
Jay Dansand
Sim, você está correto, eu editei a minha resposta original
phylanx
7

ok, solução sem arquivos temporários ou qualquer coisa:

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

é semelhante ao que os outros mencionaram, mas aqui você não precisa de um arquivo real, esta parte do comando falsifica o arquivo: <(echo ...) (observe que não há espaço no meio de<(

santiago arizti
fonte
isso não funciona se você já tem um .my.cnfarquivo em seu ~/.com uma entrada de senha
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

Para ver o que o mysql_config_editor escreveu no arquivo .mylogin.cnf, use o comando print:

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

O comando print exibe cada caminho de logon como um conjunto de linhas começando com um cabeçalho de grupo indicando o nome do caminho de logon entre colchetes, seguido pelos valores das opções para o caminho de logon. Os valores da senha são mascarados e não aparecem como texto não criptografado.

Conforme mostrado nos exemplos anteriores, o arquivo .mylogin.cnf pode conter vários caminhos de logon. Dessa maneira, o mysql_config_editor facilita a configuração de várias “personalidades” para conectar-se a diferentes servidores MySQL. Qualquer um desses itens pode ser selecionado posteriormente, usando a opção --login-path quando você invoca um programa cliente. Por exemplo, para conectar-se ao servidor local, use este comando:

shell> mysql --login-path=local

Para conectar-se ao servidor remoto, use este comando:

shell> mysql --login-path=remote
Beta
fonte
E se eu quiser executar um comando mysqldump como usuário de dados www? www-data não possui diretório inicial ... como configuro o mysql_config_editor para o usuário www-data?
lewis4u 29/02
5

De 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
Nestor Urquiza
fonte
3

Outra alternativa é usar o sshpass para chamar o mysql, por exemplo:

sshpass -p topsecret mysql -u root -p username -e 'statement'
lewiz
fonte
Parece funcionar, mas você precisa remover o 'nome de usuário' da linha de comando, não é?
e2-e4
3

Um script de solução alternativa simples. Nomeie esse "mysql" e coloque-o no seu caminho antes de "/ usr / bin". Variantes óbvias para outros comandos ou se o texto do aviso for diferente.

#!/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
David G.
fonte
3
Embora essa resposta seja um pouco complicada, eu a votei apenas porque me importo demais em ver respostas que não estão explicitamente erradas ou que são um pouco não convencionais recebendo votos negativos sem comentários! Não é de admirar que David não tenha respondido a outras perguntas! Ele entrou em cena e tentou ajudar com uma solução inovadora e foi criticado sem explicar o porquê! Downuoters anônimos da FU que não deixam comentários!
Jeremy Davis
3
+1 concorda Jeremy Davis. Isso é complicado, mas quando deixada sem outra opção, isso pode ser aceitável. Definitivamente, não está errado, ao contrário de desativar os avisos, que devem ser a idéia mais estúpida de todos os tempos!
Ben McIntyre
1
@JeremyDavis Sim, isso foi complicado, principalmente porque eu queria mostrar o trabalho. Poderia ser feito sem parênteses, mas poderia ter sido menos claro. Esta foi também a minha primeira atividade de não leitura em todas as trocas de pilhas ... depois da qual não toquei por muito tempo. Seu comentário foi definitivamente apreciado.
David G.
@DavidG. - Que bom que meu comentário foi de grande valor para você. Também é bom ver que você voltou e que sua resposta agora está em território positivo. Pessoalmente, não acho que a votação sem comentários deva ser permitida ... Como alguém pode aprender quando é criticado por tentar ?!
Jeremy Davis
Dito isto, revendo sua resposta, não estou convencido de que uma solução permanente (essencialmente envolvendo o mysql) para um problema temporário (suprimindo uma mensagem de erro para uso em um único script) seja o melhor caminho a seguir. O empacotamento mysql da IMO em uma função dentro do script (usando seu método aqui seria bom) é uma abordagem superior. Meu 2c ... :)
Jeremy Davis
3

Aqui está uma solução para o Docker em um script / bin / sh:

docker exec [MYSQL_CONTAINER_NAME] sh -c 'exec echo "[client]"> /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'

Substitua [MYSQL_CONTAINER_NAME] e verifique se a variável de ambiente MYSQL_ROOT_PASSWORD está definida no seu contêiner.

Espero que ajude você como se pudesse me ajudar!

pcmanprogrammeur
fonte
Não é ruim. Acabei de usar uma chamada com retorno, por exemplo, docker exec [MYSQL_CONTAINER_NAME] sh -c 'exec echo "[client] [RETURN HERE] password=pa55" > /root/defaults'usando a opção --defaults-filejá pega raiz também.
Matthew Wilcoxson
3

Você também pode redirecionar a saída STDERR de erro padrão para / dev / null

Então faça:

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

Joseph Shih
fonte
7
Eu evitaria esse método como esse, uma vez que dificultaria a
detecção de
1

Pessoalmente, eu uso o wrapper de script para capturar esse erro. Aqui está um exemplo de código:

#!/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
E
fonte
1

Para o PowerShell ( pwsh, não bash), essa foi uma solução bastante complexa ... Minha primeira tentativa foi encerrar as chamadas mysqlem uma try/catchfunção, mas devido a algum comportamento estranho no tratamento de erros do PowerShell , isso não era viável.

A solução foi substituir o $ErrorActionPreferenceapenas o tempo suficiente para combinar e captura STDERRe STDOUTe analisar para a palavra ERRORe re-lance conforme necessário. O motivo pelo qual não conseguimos capturar e liberar "^mysql.*Warning.*password"é porque o PowerShell manipula e gera o erro como um fluxo, portanto, você deve capturar tudo para filtrar e lançar novamente. : /

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

Nota: O PowerShell está disponível para Unix, portanto, esta solução é multiplataforma. Pode ser adaptado a bashalgumas pequenas modificações de sintaxe.

Aviso: Existem dezenas de casos extremos nos quais isso não funcionará, como mensagens de erro ou instruções que não sejam do inglês que retornam a palavra para ERRORqualquer lugar da saída, mas foi o suficiente para engolir o aviso de uma chamada básica mysqlsem bombardear o script inteiro. Espero que outros achem isso útil.

Seria bom se mysqlsimplesmente adicionasse uma opção para suprimir esse aviso.

tresf
fonte
1

Se você usa o Rundeck para agendar suas tarefas ou qualquer outra plataforma em que solicita um mylogin.cnfarquivo, usei com êxito o seguinte código de shell para fornecer um novo local para o arquivo antes de prosseguir com as chamadas 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")

Onde MYSQL_TEST_LOGIN_FILEé uma variável de ambiente que pode ser configurada para um caminho de arquivo diferente do padrão.

Isso é especialmente útil se você estiver executando um processo bifurcado e não puder mover ou copiar arquivos para o $HOMEdiretório.

Veja a documentação aqui.

Patrick.SE
fonte
0

a melhor solução é usar o alias:

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

Por exemplo, coloque isso em seu script:

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

depois, no seu script, para carregar um banco de dados:

drupal-mysql database_name < database_dump.sql

para executar uma instrução:

drupal-mysql -e "EXEC SOMESTATEMENT;"
Neil Davis
fonte
então unalias the aliaas:
Neil Davis
Para sua informação, você não pode usar o alias se estiver chamando o mysql dentro de uma função dentro do script.
user3616725
0

Defina o ajudante:

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

Use-o:

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

Tachaan! Seu código é limpo e agradável de ler

(testado com bash)

volingas
fonte
-1

Outra solução (de um script, por exemplo):

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

A -i''opção está aqui para compatibilidade com o Mac OS X. Os sistemas operacionais UNIX padrão podem usar-i

Benoit Duffez
fonte
1
A senha ainda está na linha de comando do 'sed', portanto permanece visível nas listagens de processos, mesmo que apenas brevemente.
Anthony
-1

O problema que tive foi usar a saída de forma condicional em um script bash.

Isso não é elegante, mas em uma janela de encaixe isso realmente não deve importar. Basicamente, tudo o que isso faz é ignorar a saída que não está na última linha. Você pode fazer o mesmo com o awk e alterar para retornar todos, exceto a primeira linha, etc.

Isso retorna apenas a última linha

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

Não suprimirá o erro, mas garantirá que você possa usar a saída de uma consulta em um script bash.

WiR3D
fonte
-1

A maneira mais fácil:

mysql -u root -p YOUR_DATABASE

Digite isso e você precisará digitar sua senha.

Nota: Sim, sem ponto e vírgula.

LukasNiessen
fonte
-3

Você pode executar o mySQL e suprimir mensagens de aviso e erro usando / dev / null, por exemplo:

# 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

Onde:

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

desfrutar!

Stan Khalipa
fonte
1
Esteja ciente de que ele suprimirá TODAS as mensagens de erro, não apenas os avisos de senha.
Simon East
-3

Funcionou para mim - apenas adicionado 2> nullapós o $(mysql_command)e suprimirá apenas as mensagens de erros e aviso.

MMG
fonte
1
Isso também significa que você não recebe um relatório quando algo der errado!
Anthony
Além disso, você provavelmente queria 2>/dev/null. Usar 2> nullapenas colocaria a saída em um arquivo chamado "null" no diretório atual.
Thelogix