在终端中使用mysql抑制警告消息,但密码以bash脚本编写


273

当我尝试从终端在MySQL上运行以下命令时:

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

执行工作按预期方式进行,但始终会发出警告:

警告:在命令行界面上使用密码可能不安全。

但是,我必须使用$password存储我的密码的环境变量()来执行上述语句,因为我想从Terminal内部在bash脚本中迭代地运行命令,并且我绝对不喜欢等待提示出现的想法并迫使我在一个脚本中输入50或100次密码。所以这是我的问题:

  • 抑制警告是否可行?该命令可以按照我所说的那样正常工作,但是当我循环并运行50或100次命令时,窗口会变得非常混乱。

  • 我应该听从警告消息并且不要在脚本中写密码吗?如果是这种情况,那么每次提示提示我输入密码时,我都必须输入密码吗?

跑步man mysql无济于事,只说

--show-warnings
导致在每个语句之后显示警告。此选项适用于交互式和批处理模式。

如果没有丢失任何内容,也没有提及如何关闭功能。

我在OS X 10.9.1 Mavericks上,并使用自制软件中的MySQL 5.6。


14
推荐的方法是将密码存储在选项文件中(类似于[client] password=my_password中的~/.my.cnf)。当然,它也有一些安全隐患,但是至少任何可以运行的人都无法访问它ps,并且您可以通过文件许可权对其进行控制。
安东·科瓦连科

4
mysql -u root password root -e "statement" > /dev/null

哦,顺便说一句,您还可以使用Python之类的东西pexcept。它可以进行终端插入,还可以处理命令给出的反馈。这样,您可以跳过该详细输出,并删除所需的实际输出:)

6
IMO推荐的方法是对做错事的人进行惩罚,以保护做错事的人。如果密码存储在脚本文件中,它将不会与ps或任何日志一起显示。这是正确的方法。将文件放在外部文件中确实可以帮助那些准备密码的人使用,但这样做一开始就很困难。同时,已经运行了多年的脚本现在失败了,我们仅仅因为在stderr中出现此警告而需要对其进行修改。
Nestor Urquiza 2015年

2
对于不明确存储密码的推荐方法,请参见dev.mysql.com/doc/refman/5.6/en/mysql-config-editor.html
安东尼

Answers:


249

如果您的MySQL客户端/服务器版本是5.6.xa以避免警告消息的方式,请使用mysql_config_editor工具:

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

然后,您可以在shell脚本中使用:

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'
Tulio 2014年

默认情况下,mysql命令行客户端将在“客户端”登录路径下显示。您可以通过进行一些小的更改来简化“ mysql -e'statement'”的说明。
Morgan Tocker 2015年

2
如果我们直接执行shell文件,但如果从crontab调用,则无法正常工作
Nabeel Arshad

1
@NabeelArshad我认为这是因为未在crontab中为用户设置“主页”(通常是ENV变量),因此在crontab中,客户端无法找到正确的〜/ .mylogin.cnf
Cristian Porta

1
@NamGVU,我不确定,但是,我相信此解决方案可以存储加密的密码。
zhekaus

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 2014年

21
制作临时.cnf文件的另一种方法是在Bash中执行此操作mysql --defaults-extra-file=<(printf "[client]\nuser = %s\npassword = %s" "$user" "$pwd") -e "statement"。由于printfBash直接执行,因此不会显示在中ps
Dave James Miller

3
我需要使用--defaults-file而不是--defaults-extra-file,因为后者优先使用〜/ .my.cnf中的设置。
罗杰·迪克

185

一种方便(但同样不安全)的方法是使用:

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

请注意,官方文档建议不要这样做。
请参见6.1.2.1最终用户密码安全准则(MySQL手册,版本5.6)

将密码存储在MYSQL_PWD环境变量中

这种指定MySQL密码的方法必须被认为是非常不安全的,并且不应该使用。某些版本的ps包含一个选项,用于显示正在运行的进程的环境。在某些系统上,如果进行了设置MYSQL_PWD,则您的密码将向运行ps的任何其他用户公开。即使在没有此类ps版本的系统上,假设用户没有其他方法可以检查进程环境也是不明智的。


6
这在我的bash脚本中不起作用:Access denied for user 'root'@'localhost' (using password: NO)
rubo77

24
在脚本中,您需要export MYSQL_PWD=whatever
骚乱2015年

2
因为查询非常快,所以选择了此选项。然后在执行查询后将其设置为伪造的东西。
TimH-Codidact '16

11
在脚本中,您无需运行export,只需将其全部放在一行上即可:MYSQL_PWD=xxxxxxxx mysql -u root -e "statement"
JD

1
@JD:适用于MySQL 16.5.7的Ubuntu 16.04。
mivk

70

如果您想在命令行中使用密码,我发现这可以过滤掉特定的错误消息:

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

它基本上是将标准错误重定向到标准输出-并使用grep删除所有与“警告:使用密码”匹配的行。

这样,您可以看到任何其他输出,包括错误。我将此用于各种shell脚本等。


对于在其他任务(例如为Capistrano部署创建Rake任务)中调用的单层任务中使用,这是一个极好的解决方案。
JakeGould '16

2
静音该消息非常简单,无需在MySQL安装程序中进行任何操作。
ajaaskel

我如何在已经有SQL重定向的mysqldump中使用它?
MacroMan

1
与此处的其他解决方案相比,这是一个非常糟糕的解决方案。如果文本更改,它的任何后续版本的MySQL都可能失败,也可能无法在其他语言环境中使用。
yktoo's

42

这是我获取bash脚本的方法,以使我的日常mysqldump数据库备份更加安全地工作。这是对克里斯蒂安·波塔(Cristian Porta)的一个很好的回答。

  1. 首先使用mysql_config_editor(与mysql 5.6+一起提供)来设置加密的密码文件。假设您的用户名是“ db_user”。从shell提示符运行:

    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

43
问题在于,这也会抑制脚本中的合法错误。
man910 2014年

4
您也可以创建一个日志文件2> /var/log/myscript.log来记录该错误。
Skamasle 2014年

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

这将启动一个期望会话,该会话可以在脚本中用于与提示进行交互

看到这篇文章


那真的是'>'的意思吗?
大卫·古德温

是的'>'意味着在那里,以便mysql_config_editor从stdout获取输入。从stdout传递到mysql_config_editor的是您希望该用户拥有的密码,如果没有'>',则发生的是解析了echo命令,并且您所看到的只是echo命令之后的所有内容
phylanx

所以,您的意思是使用管道运算符“ |”,对吗?至少,在* nix和DOS中,“>”将捕获STDOUT并将其写入当前工作目录中名为“ mysql_config_editor”的文件中。
杰伊·丹桑

是的,您是对的,我已经编辑了我的原始答案
phylanx 2014年

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

如果我想以www-data用户身份执行mysqldump命令怎么办?www-data没有主目录...如何为www-data用户设置mysql_config_editor?
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'

似乎可以使用,但是您必须从命令行中删除“用户名”,不是吗?
e2-e4

3

一个简单的workaroud脚本。将此名称命名为“ 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
尽管这个答案有些令人费解,但我只是对其进行了投票,因为它让我非常震惊,以至于看到的答案并没有明显的错误,或者有点不合常规而毫无评论地落选了!难怪大卫还没有回答其他问题!他跳了进来,并尝试提供新颖的解决方案,但遭到猛烈抨击,没有解释原因!FU不愿发表评论的匿名人士!
杰里米·戴维斯

3
+1同意Jeremy Davis。这令人费解,但是如果没有其他选择,这可能是可以接受的。绝对没有错,不同于关闭警告,警告必须是迄今为止最愚蠢的想法!
本·麦金太尔

1
@JeremyDavis是的,这令人费解,主要是因为我想展示作品。可以在没有任何括号的情况下完成此操作,但可能不太清楚。这也是我有史以来第一次在所有堆栈交换中都处于非读取状态……此后很长一段时间我都没有碰它。您的评论绝对值得赞赏。
David G.

@DavidG。-很高兴我的评论对您很有价值。也很高兴看到您回来了,并且您的答案现在处于积极状态。就我个人而言,我不应该允许不发表评论就投下赞成票……当一个人因为去尝试而受到抨击时,任何人都打算学习吗?
杰里米·戴维斯

话虽如此,重新审视您的答案,我不认为永久解决方案(本质上是将mysql包装)解决临时问题(抑制在单个脚本中使用的错误消息)是最好的方法。IMO将mysql包装在脚本中的函数中(在这里使用您的方法就可以了)是一种更好的方法。我的2c ... :)
杰里米·戴维斯

3

这是脚本/ bin / sh中的Docker解决方案:

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

替换[MYSQL_CONTAINER_NAME],并确保在容器中设置了环境变量MYSQL_ROOT_PASSWORD。

希望它能对您有所帮助!


不错。我只用了一个回叫电话,例如,docker exec [MYSQL_CONTAINER_NAME] sh -c 'exec echo "[client] [RETURN HERE] password=pa55" > /root/defaults'使用,--defaults-file它也已经占了上风。
马修·威尔考克森

3

您也可以将标准错误STDERR输出重定向到/ dev / null

所以做:

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


7
我会避免使用这种方法,因为这样会使合法错误更加难以发现
Vladimir Hraban 18/12/10

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),这是一个相当不错的解决方案...我的第一个尝试是将对它们的调用包装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仅添加一个选项来禁止显示此警告,那就太好了。


1

如果您碰巧使用Rundeck来安排任务,或者使用其他平台来请求mylogin.cnf文件,那么在继续执行sql调用之前,我已经成功使用了以下Shell代码为文件提供了新位置:

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目录中,则此功能特别有用。

请参阅此处的文档。


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

然后取消别名:
Neil Davis

仅供参考,如果您要在脚本中的函数内调用mysql,则不能使用别名。
user3616725 '19

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

大妈!您的代码干净而且易于阅读

(经过bash测试)


-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 OS可以直接使用-i


1
密码仍然在“ sed”的命令行上,因此即使只是短暂地在进程列表中仍然可见。
安东尼

-1

我遇到的问题是在bash脚本中有条件地使用输出。

这不是很优雅,但是在docker env中,这实际上并不重要。基本上所有这些操作都是忽略不在最后一行的输出。您可以使用awk进行类似操作,并更改为返回除第一行等以外的所有内容。

这只会返回最后一行

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

它不会消除该错误,但是会确保您可以在bash脚本中使用查询的输出。


-1

最简单的方法:

mysql -u root -p YOUR_DATABASE

输入此密码,您将需要输入密码。

注意:是的,没有分号。


-3

您可以使用/ dev / null执行mySQL并禁止显示警告和错误消息,例如:

# 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
请注意,它将禁止所有错误消息,而不仅仅是那些密码警告。
Simon East

-3

它对我有用-刚刚添加2> null$(mysql_command),它将仅抑制错误和警告消息。


1
这也意味着如果出现其他问题,您将不会得到报告!
安东尼

另外,您可能想要2>/dev/null。使用2> null只会将输出放入当前目录中的一个名为“ null”的文件中。
thelogix
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.