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

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

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

执行按预期工作,但它总是发出一个警告:

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

然而,我必须使用存储密码的环境变量($password)来执行上面的语句,因为我想在终端内以bash脚本迭代地运行命令,而且我绝对不喜欢等待提示显示并强迫我在单个脚本中输入密码50或100次的想法。我的问题是:

  • 压制警告可行吗?如我所述,该命令可以正常工作,但是当我循环并运行该命令50或100次时,窗口变得非常混乱。

  • 我应该遵守警告信息,不写我的密码在我的脚本?如果是这样的话,那么每次提示时我都必须输入密码吗?

运行man mysql没有帮助,只说

< p > --show-warnings < br > 在每条语句后显示警告(如果有的话)。该选项适用于交互和批处理模式

也没有提到如何关闭功能,如果我没有错过什么。

我使用的是OS X 10.9.1 Mavericks,使用的是自制的MySQL 5.6。

389677 次浏览

如果您的MySQL客户端/服务器版本是5.6。使用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"

另一种方法是使用sshpass调用mysql,例如:

sshpass -p topsecret mysql -u root -p username -e 'statement'

您还可以在脚本中运行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}
"

这将启动一个expect会话,该会话可用于脚本中与提示符交互

见this post .

最简单的方法是

mysql -u root -pMYPASSWORD -e "show databases" 2>/dev/null

我使用的是:

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

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

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

注意,官方文件不建议这样做。
看到6.1.2.1密码安全终端用户指南(Mysql Manual for Version 5.6): < / p >

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

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

另一个解决方案(例如,来自脚本):

 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

你可以使用/dev/null来执行mySQL并删除警告和错误消息 例如:< / p >
# 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

享受吧!

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数据库备份的bash脚本更安全地工作。这是一个扩展克里斯蒂安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_user "到您在服务器上的用户名。

  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
    

不再暴露密码。

就我个人而言,我使用脚本包装器来捕获该错误。下面是代码示例:

#!/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

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

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

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

它基本上是将标准错误重定向到标准输出——并使用grep删除与“Warning: using a password”匹配的所有行。

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

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

这是不优雅的,但在docker环境中,这应该真的不重要。 基本上,所有这些操作都忽略了不在最后一行上的输出。 你可以用awk做类似的事情,并更改为返回除第一行以外的所有内容,等等

这只返回最后一行

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

它不会抑制错误,但它将确保您可以在bash脚本中使用查询的输出。

一个简单的变通脚本。命名为“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
这对我很有效 刚刚在$(mysql_command)之后添加了2> null,它将只抑制错误和警告消息

下面是Docker在/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-databases'

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

希望它能像帮助我一样帮助你!

对于PowerShell (pwsh,而不是bash),这是一个相当土豪的解决方案…我的第一次尝试是在try/catch函数中包装对mysql的调用,但由于一些PowerShell错误处理中的奇怪行为,这是不可行的。

解决方案是覆盖$ErrorActionPreference足够长的时间来组合和捕获STDERRSTDOUT,并解析单词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只是添加了一个选项来抑制这个警告,那就太好了。

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

所以只要这样做:

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

最好的解决方案是使用别名:

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

好的,没有临时文件的解决方案

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

它类似于其他人提到的,但在这里你不需要一个实际的文件,这部分命令伪造文件:<(echo ...) (注意<(中间没有空格

最简单的方法:

mysql -u root -p YOUR_DATABASE

输入这个,你需要输入你的密码。

注意:是的,没有分号。

定义帮助者:

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 测试)

如果您碰巧使用 Rundeck 来调度您的任务,或者使用任何其他平台来请求 mylogin.cnf文件,我已经成功地使用下面的 shell 代码在继续 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")

其中,abc0是一个环境变量,可以设置为与默认路径不同的文件路径。

如果您在一个分叉进程中运行并且无法将文件移动或复制到 $HOME目录,那么这种方法尤其有用。

请参阅这里的文档。

很简单,这是我的工作。

export MYSQL_PWD=password; mysql --user=username -e "statement"

MYSQL_PWDMySQL 直接或间接使用的环境变量之一。

来自文件:

MYSQL _ PWD-连接到 mysqld 时的默认密码。使用这个密码是不安全的。参见 第6.1.2.1节「最终用户密码保安指引」

@ david-g 给出的答案非常好,但是至少 BSD grep会将 [Warning]解释为单个字符的正则表达式表示(匹配单词 Warning中的任何一个字符)。

对于我的脚本,我使用相同的方法,包装在一个函数中(为了简单起见,只匹配字符串的一部分) :

mysql() {
(
(
(
(
(
/usr/local/bin/mysql "$@"
) 1>&9
) 2>&1
) | grep -v 'Using a password on the command line interface can be insecure.'
) 1>&2
) 9>&1
}


out=$(mysql ...... 2>&1)
rc=$?

上面的代码将使用一组选项调用 mysql,将经过过滤的 stderr 重定向到 stdout,并捕获 $opt中的组合输出和 $rc中的退出代码。