#!/bin/bash
# 执行提示 expect 命令找不到,使用 yum install expect 安装。
# 以下链接信息都是测试环境,需要后期手工调整。
# TDSQL 数据库连接信息
# TDSQL_PASSWORD 密码用单引号,不用双引号 不进行转义,防止密码中有特殊字符被转义
TDSQL_HOST="数据库连接的IP"
TDSQL_PORT="数据库连接的端口"
TDSQL_USER="数据库连接的用户名"
TDSQL_PASSWORD='数据库连接的密码'
TDSQL_DATABASE="数据库连接的库"
# 多个表名,用空格分隔
TDSQL_TABLES="qw_thondinfo gs_thondinfo"
# 导出文件的本地路径(服务器上的本地目录,绝对路径)
LOCAL_DIR="/home/sql/"
TIMESTAMP=$(date +%Y%m%d%H%M%S)
# SFTP 目标服务器信息(SFTP REMOTE_DIR 目录必须是已经存在的)
SFTP_HOST="目标服务器的IP"
SFTP_PORT="目标服务器提供SFTP用户访问的端口号"
SFTP_USER="SFTP 连接的用户名"
SFTP_PASSWORD='SFTP 连接的密码'
SFTP_REMOTE_DIR="/test"
# 遍历每个表进行导出
for table in $TDSQL_TABLES; do
LOCAL_SQL_FILE="${LOCAL_DIR}${table}_${TIMESTAMP}.sql"
mysqlpump -h $TDSQL_HOST -P $TDSQL_PORT -u $TDSQL_USER -p"$TDSQL_PASSWORD" $TDSQL_DATABASE $table > $LOCAL_SQL_FILE
if [ $? -eq 0 ]; then
echo "表 $table 数据导出成功,导出文件为: $LOCAL_SQL_FILE"
else
echo "表 $table 数据导出失败,请检查数据库连接信息。"
continue
fi
# 上传文件到 SFTP 服务器
expect <<EOF
spawn sftp -P $SFTP_PORT $SFTP_USER@$SFTP_HOST
expect "password:"
send "$SFTP_PASSWORD\n"
expect "sftp>"
send "put $LOCAL_SQL_FILE $SFTP_REMOTE_DIR\n"
expect "sftp>"
send "bye\n"
expect eof
EOF
if [ $? -eq 0 ]; then
echo "表 $table 的导出文件上传到 SFTP 服务器成功。"
else
echo "表 $table 的导出文件上传到 SFTP 服务器失败,请检查 SFTP 连接信息。"
fi
done
[root@50-131-226-215 sql]# sh exportSqlToSftp.sh
mysqlpump: [Warning] Using a password on the command line interface can be insecure.
mysqlpump: [ERROR] 1045: Proxy ERROR: Access denied for user 'airp_iopc'@'50.131.226.215' (using password: 'YES'): username or password error when trying to connect
表 qw_thondinfo 数据导出失败,请检查数据库连接信息。
mysqlpump: [Warning] Using a password on the command line interface can be insecure.
mysqlpump: [ERROR] 1045: Proxy ERROR: Access denied for user 'airp_iopc'@'50.131.226.215' (using password: 'YES'): username or password error when trying to connect
排查思路:
根据报错信息,是执行连接数据库的命令时,密码不对。
但是将 数据库的密码单独拿出来用 命令连接可以连接成功:
mysql -h 192.168.1.100 -P 3307 -u admin -p mydatabase
-h 192.168.1.100
: 指定远程服务器 IP 或域名-P 3307
: 指定非默认端口(若端口是默认的 3306
,可省略 -P 3307
)-u admin
: 使用用户名 admin
mydatabase
: 直接进入名为 mydatabase
的数据库说明密码本身没有问题。
既然密码本身没有问题,脚本文件上的密码也对上没有问题。
那就有可能是在执行脚本文件的过程中出了问题,提示密码错误。
考虑到“密码”的特殊性,有可能会包含特殊字符。比如 : 123]#%&$。
$
, #
, &
, ]
等)时,直接使用 $TDSQL_PASSWORD
可能会因 Shell 解析或命令行参数处理异常导致密码被截断或转义错误。Shell 中某些字符(如 $
, #
, &
)具有特殊含义,若未正确处理会导致密码解析错误。
示例脚本:
# 错误写法
TDSQL_PASSWORD="123]#%&$"
mysql -u root -p$TDSQL_PASSWORD -h localhost
比如以下特殊字符:
$
符号会被解析为变量替换的开始(即使后面没有有效变量名)。#
在 Shell 中表示注释,其后的内容会被忽略。&
会导致命令在后台执行,中断参数传递。解决方案:用双引号包裹密码变量,同时在定义密码变量的时候用单引号包裹实际密码,避免特殊字符被 Shell 解析:
TDSQL_PASSWORD='123]#%&$'
...
mysql -u root -p"$TDSQL_PASSWORD" -h localhost # 正确写法
-[root@950-131-226-215 sql]# sh exportSqlToSftp
mysqldump: [Warning] Using a password on the command line interface can be insecure.
Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don't want to restore GTIDs, pass --set-gtid-purged=OFF.
complete dump, pass --all-databases --triggers --routines --events
exportSqlToSftp.sh:行37: expect: 未找到命令
mysql/sql tbondbond数据导出成功, 导出文件为: /home/sql/tbondbond_20250514152931.sql
mysqldump: [Warning] Using a password on the command line interface can be insecure.
Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don't want to restore GTIDs, pass --set-gtid-purged=OFF.
complete dump, pass --all-databases --triggers --routines --events
exportSqlToSftp.sh:行37: expect: 未找到命令
mysql/sql tbondbond数据导出成功, 导出文件为: /home/sql/tbondbond_20250514152948.sql
exportSqlToSftp.sh:行37: expect: 未找到命令
tbondbond数据导出失败, 请检查SFTP连接信息。
以上报错是 执行提示 expect 命令找不到,使用 yum install expect 安装。
直接在服务器上执行命令:
yum install expect
根据提示,一路点 yes 就行。
[root@50-131-226-215 sql]# sh exportSqlToSftp.sh
mysqldump: [Warning] Using a password on the command line interface can be insecure.
Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions.
complete dump, pass --all-databases --triggers --routines --events.
表 qy_tbondinfo 数据导出成功, 导出文件为: /home/sql/qy_tbondinfo_20250514153157.sql
spawn sftp -P 10022 airp_lc_sftp@50.131.232.114
ssh: connect to host 50.131.232.114 port 10022: Connection refused
Connection closed.
Connection closed
send: spawn id exp4 not open
while executing
'send "Qw@3124!\n"'
表 qy_tbondinfo 的导出文件上传到 SFTP 服务器失败, 请检查 SFTP 连接信息。
mysqldump: [Warning] Using a password on the command line interface can be insecure.
Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions.
complete dump, pass --all-databases --triggers --routines --events.
表 gs_tbondinfo 数据导出成功, 导出文件为: /home/sql/gs_tbondinfo_20250514153157.sql
spawn sftp -P 10022 airp_lc_sftp@50.131.232.114
ssh: connect to host 50.131.232.114 port 10022: Connection refused
Connection closed
Connection closed.
send: spawn id exp4 not open
while executing
'send "Qw@3124!\n"'
表 gs_tbondinfo 的导出文件上传到 SFTP 服务器失败, 请检查 SFTP 连接信息。
[root@50-131-226-215 sql]#
将脚本文件中的 sftp 命令单独拿出来执行发现报错,命令如下:
sftp -P 远程服务器的端口号 sftp的用户名@sftp用户连接的远程服务器IP
由于之前直接用 sftp sftp用户名@远程ip
命令成功过,所以排除是sftp的用户名 和 密码的问题。
对比两个命令的差异,报错的命令因为多了端口号,所以有可能是 该远程服务器该端口没有开放访问权限或者防火墙拦截了。
又搜了下 sftp sftp用户名@远程ip
不传端口号会使用默认的端口号连接,所以会成功。
sftp root@ip
和 sftp -P port root@ip
都是用于通过 SSH 文件传输协议(SFTP)连接到远程服务器的命令,二者主要区别如下:
sftp root@ip
:不指定端口时,sftp
命令默认使用 SSH 的标准端口 22
来建立连接。如果远程服务器的 SSH 服务运行在标准端口上,该命令可正常连接 。sftp -P port root@ip
:-P
选项用于显式指定连接远程服务器的端口号,port
是具体端口数值。当远程服务器的 SSH 服务运行在非标准端口(不是 22
端口 )时,就需要使用该形式指定正确端口才能成功连接。例如 sftp -P 2222 root@192.168.1.100
,表示连接 192.168.1.100
这台服务器的 2222
端口。sftp root@ip
:适用于远程服务器使用默认 22
端口运行 SSH 服务的常规场景,使用相对简洁。sftp -P port root@ip
:适用于远程服务器修改了默认 SSH 端口的场景。为增强安全性,很多管理员会将 SSH 服务端口修改为其他端口,此时就必须用 -P
选项指定实际端口才能连接。DeepSeek 优化脚本,将原来导出成sql文件,改成导出生成 .gz 格式的文件
#!/bin/bash
set -o pipefail # 确保管道中任意命令失败时整个管道返回非零状态
# 检查 expect 是否安装
if ! command -v expect &> /dev/null; then
echo "检测到 expect 未安装,正在自动安装..."
yum install -y expect
fi
# TDSQL 数据库连接信息
TDSQL_HOST="数据库连接的IP"
TDSQL_PORT="数据库连接的端口"
TDSQL_USER="数据库连接的用户名"
TDSQL_PASSWORD='数据库连接的密码' # 保持单引号避免特殊字符转义
TDSQL_DATABASE="数据库连接的库"
TDSQL_TABLES="qw_thondinfo gs_thondinfo" # 表名用空格分隔
# 导出文件的本地路径(绝对路径)
LOCAL_DIR="/home/sql/"
TIMESTAMP=$(date +%Y%m%d%H%M%S)
# SFTP 服务器信息
SFTP_HOST="目标服务器的IP"
SFTP_PORT="目标服务器的SFTP端口"
SFTP_USER="SFTP用户名"
SFTP_PASSWORD='SFTP密码'
SFTP_REMOTE_DIR="/test"
# 确保本地目录存在
mkdir -p "$LOCAL_DIR"
# 遍历每个表进行导出和压缩
for table in $TDSQL_TABLES; do
LOCAL_GZ_FILE="${LOCAL_DIR}${table}_${TIMESTAMP}.sql.gz"
# 使用 mysqlpump 导出并直接压缩为 .gz
mysqlpump -h "$TDSQL_HOST" -P "$TDSQL_PORT" -u "$TDSQL_USER" -p"$TDSQL_PASSWORD" \
"$TDSQL_DATABASE" "$table" | gzip > "$LOCAL_GZ_FILE"
if [ $? -eq 0 ]; then
echo "表 $table 数据导出并压缩成功,文件: $LOCAL_GZ_FILE"
else
echo "表 $table 导出或压缩失败,请检查数据库连接或权限。"
rm -f "$LOCAL_GZ_FILE" # 删除可能生成的空文件
continue
fi
# 上传 .gz 文件到 SFTP
expect <<EOF
spawn sftp -P "$SFTP_PORT" "$SFTP_USER@$SFTP_HOST"
expect "password:"
send "$SFTP_PASSWORD\r"
expect "sftp>"
send "put $LOCAL_GZ_FILE $SFTP_REMOTE_DIR\r"
expect "sftp>"
send "bye\r"
expect eof
EOF
if [ $? -eq 0 ]; then
echo "文件 $LOCAL_GZ_FILE 上传成功。"
else
echo "文件 $LOCAL_GZ_FILE 上传失败,请检查 SFTP 配置。"
fi
done