ChatGPT解决这个技术问题 Extra ChatGPT

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

当我尝试从终端中在 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。

推荐的方法是将您的密码存储在一个选项文件中(例如 ~/.my.cnf 中的 [client] password=my_password)。当然,它也有一些安全隐患,但至少 任何人 都无法运行 ps,并且您可以通过文件权限控制它。
mysql -u root password root -e "statement" > /dev/null ?
哦,顺便说一句,您也可以使用 Python pexcept 之类的东西。它可以进行终端插入,也可以处理命令给出的反馈。这样你就可以跳过那个详细的输出并去掉你想要的实际输出:)
推荐的方式 IMO 惩罚做正确事情的人以保护做错事情的人。如果密码存储在脚本文件中,它将不会显示在 ps 或任何日志中。这是做到这一点的正确方法。将文件放在外部文件中确实有助于那些会 cron 密码但开始时不好的人。与此同时,已经运行多年的脚本现在失败了,我们需要修改它们,因为这个警告出现在标准错误中。
对于不明文存储密码的推荐方法,详见dev.mysql.com/doc/refman/5.6/en/mysql-config-editor.html

G
Giacomo1968

如果您的 MySQL 客户端/服务器版本是 5.6.xa 避免 WARNING 消息的方法,则使用 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"

请记住,--login-path 必须位于所有其他参数之前。我正在尝试 mysqldump --tables --login-path=local 并收到错误 unknown variable 'login-path=local'
如果我们直接执行 shell 文件,这可以正常工作,但如果从 crontab 调用则无法正常工作
@NabeelArshad 我认为这是因为在您的 crontab 中未设置用户的“家”(一般为 ENV 变量),因此在 crontab 中客户端无法找到正确的 ~/.mylogin.cnf
@NamGVU,我不确定,但是,我相信这个解决方案存储了加密的密码。
那么在所有这些评论之后,适用于从 crontab 调用的脚本的解决方案是什么?
l
luke

我使用类似的东西:

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


注意:--defaults-extra-file 必须是第一个选项,否则 mysql 会报错 mysqldump: unknown variable 'defaults-extra-file
已接受答案的绝佳替代方案。绝对不要设置 MYSQL_PWD 变量....
对于 5.6 以下的版本绝对是一个不错的选择。否则,我会接受公认的答案。
制作临时 .cnf 文件的另一种方法是在 Bash 中执行此操作:mysql --defaults-extra-file=<(printf "[client]\nuser = %s\npassword = %s" "$user" "$pwd") -e "statement"。由于 printf 是由 Bash 直接执行的,因此它不会显示在 ps 中。
我需要使用 --defaults-file 而不是 --defaults-extra-file,因为后者优先考虑 ~/.my.cnf 中的设置。
C
Community

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

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

请注意,官方文档建议不要这样做。
请参阅 6.1.2.1 End-User Guidelines for Password Security (Mysql Manual for Version 5.6)

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


这在我的 bash 脚本中不起作用:Access denied for user 'root'@'localhost' (using password: NO)
在脚本中,您需要 export MYSQL_PWD=whatever
因为我的查询非常快,所以我选择了这个选项。然后我在执行查询后将其设置为虚假的。
在不需要运行 export 的脚本中,只需将其全部放在一行中:MYSQL_PWD=xxxxxxxx mysql -u root -e "statement"
MYSQL_PWD 记录在 5.5、5.6 和 5.7 客户端文档中,但从 8.0 文档中省略。
j
johnmontfx

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

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

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

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


这是一个出色的解决方案,可用于在其他任务中调用的单线任务,例如为 Capistrano 部署创建 Rake 任务。
将消息静音非常简单,无需在 MySQL 设置中进行任何操作。
在我已经有 SQL 重定向的情况下,我将如何将它与 mysqldump 一起使用?
与这里的其他解决方案相比,这是一个非常糟糕的解决方案。如果文本更改,它可能会在任何后续版本的 MySQL 中失败,也可能无法在另一个语言环境中工作。
如何将错误重定向回标准错误? (例如 1>&2
B
Buttle Butkus

以下是我如何让我的 bash 脚本让我的日常 mysqldump 数据库备份更安全地工作。这是 Cristian Porta 伟大的 answer 的扩展。

首先使用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”更改为你的用户名。从此更改您的 bash 脚本:mysqldump -u db_user -pInsecurePassword my_database | gzip > db_backup.tar.gz 到这个:mysqldump --login-path=local my_database | gzip > db_backup.tar.gz

没有更多暴露的密码。


J
JavaGuy

最简单的方法是

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

问题是这也会抑制脚本中的合法错误。
您还可以创建一个日志文件 2>/var/log/myscript.log 来记录该错误。
使用 2>/dev/null | grep -v "mysql: [Warning] Using a password on the command line interface can be insecure." 仅抑制有问题的警告
由于 2>/dev/null 已经重定向到 /dev/null - grep 在那里没有做任何事情。重定向需要转到 2>&1 来过滤掉这个单一的警告。
Я
Ярослав Рахматуллин

这很简单。这对我来说是工作。

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

MYSQL_PWDenvironment variables that are used directly or indirectly by MySQL 之一。

从文档:

MYSQL_PWD - 连接到 mysqld 时的默认密码。使用它是不安全的。请参见第 6.1.2.1 节“密码安全的最终用户指南”。


这是这里唯一正确的答案!奇迹般有效 :)
不推荐使用 MYSQL_PWD 环境变量来指定 MySQL 密码。
s
santiago arizti

好的,没有临时文件或任何东西的解决方案:

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

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


如果您的 ~/. 中已经有一个带有密码条目的 .my.cnf 文件,这将不起作用
我认为这没有得到任何相反的评论,它是相对安全的。如果是这种情况,我认为这是一个很棒的解决方法。
@stepanian mysql[dump] 报告的安全问题来自密码将出现在正在运行的进程列表中的事实(请参阅 ps -ef | grep mysql)。如果您将它放在该语句中所示的变量中,则可能没问题。但是,如果您有明文而不是 $password 的密码,那也不会好多少(回显会非常快,因此作为黑客,在这种情况下更难获取信息,但仍有可能)。
C
Community

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

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

See this post


那'>'真的应该在那里吗?
是的 '>' 应该在那里,以便 mysql_config_editor 从标准输出中获取输入。从 stdout 传递到 mysql_config_editor 的是您希望该用户拥有的密码 如果没有“>”,那么会发生 echo 命令被解析,您将看到的只是 echo 命令之后的所有内容
那么,您的意思是使用管道运算符“|”,对吗?至少,在 *nix 和 DOS 中,“>”将捕获 STDOUT 并将其写入当前工作目录中名为“mysql_config_editor”的文件中。
是的,你是对的,我已经编辑了我原来的答案
D
David G.

一个简单的工作脚本。将此命名为“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

虽然这个答案有点令人费解,但我只是对其投了赞成票,因为看到没有明确错误或有点不合常规的答案让我非常讨厌,而没有评论却被否决了!难怪大卫没有回答任何其他问题!他跳了进去,试图帮助一个新颖的解决方案,却被猛烈抨击,没有解释为什么! FU 匿名投票者不发表评论!
+1 同意杰里米戴维斯。这是令人费解的,但如果没有其他选择,这可能是可以接受的。这绝对没有错,不像关闭警告,这是有史以来最愚蠢的想法!
@JeremyDavis 是的,这很复杂,主要是因为我想展示作品。它可以不带任何括号来完成,但可能不太清楚。这也是我在所有堆栈交换中的第一次非阅读活动......之后我很长时间没有碰它。您的评论绝对受到赞赏。
@大卫G。 - 很高兴我的评论对你有价值。很高兴看到你回来了,你的答案现在是积极的。就个人而言,我认为不应该允许在没有评论的情况下投反对票......当他们因为尝试而受到抨击时,任何人都打算学习吗?!
话虽如此,重新查看您的答案,我不相信临时问题(在单个脚本中抑制错误消息以供使用)的永久解决方案(基本上包装 mysql)是最好的方法。 IMO 将 mysql 包装在脚本中的函数中(在此处使用您的方法就可以了)是一种更好的方法。我的 2c ... :)
J
Joseph Shih

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

所以就这样做:

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


我会避免这种方法,因为它会使合法错误更难被发现
B
Beta
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?
N
Nestor Urquiza

来自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

l
lewiz

另一种选择是使用 sshpass 来调用 mysql,例如:

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

似乎可以工作,但是您必须从命令行中删除“用户名”,不是吗?
C
Community

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

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。

希望它会帮助你喜欢它可以帮助我!


不错。我刚刚使用了一个带有返回的调用,例如 docker exec [MYSQL_CONTAINER_NAME] sh -c 'exec echo "[client] [RETURN HERE] password=pa55" > /root/defaults' 使用 --defaults-file 它也已经获得了 root 权限。
v
volingas

定义助手:

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


A
And

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

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

t
tresf

对于 PowerShell(pwsh,而不是 bash),这完全是一个 rube-goldberg 解决方案...我的第一次尝试是将对 mysql 的调用包装在 try/catch 函数中,但由于某些 strange behavior in PowerShell error handling ,这是不可行的。

解决方案是将 $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 简单地添加一个选项来禁止此警告,那就太好了。


P
Patrick.SE

如果您碰巧使用 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")

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

如果您在分叉进程中运行并且无法将文件移动或复制到 $HOME 目录,这将特别有用。

See documentation here.


W
WiR3D

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

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

这只返回最后一行

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

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


N
Neil Davis

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

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,则不能使用别名。
别名不会隐藏警告,现在我可以在您的控制台中输入“别名”并查看您的密码...
l
ltning

@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 中的退出代码。


B
Benoit Duffez

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

 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


密码仍然在“sed”的命令行上,因此在进程列表中仍然可见,即使只是短暂的。
M
Mr. Pyramid

它对我有用 - 只是在 $(mysql_command) 之后添加了 2> null,它只会抑制错误和警告消息。


这也意味着当出现其他问题时您不会收到报告!
此外,您可能想要 2>/dev/null。使用 2> null 只会将输出放入当前目录中名为“null”的文件中。
S
Stan Khalipa

您可以使用 /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

请享用!


请注意,它将抑制所有错误消息,而不仅仅是那些密码警告。
R
RobC

最简单的方法:

mysql -u root -p YOUR_DATABASE

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

注意:是的,没有分号。


如果您在控制台上,这将有效。如果我每天运行一次转储,我不想在控制台...