Shell脚本执行pgloader时变量未替换及索引错误问题
问题分析与解决
问题根源
- 密码变量解析错误:
pgsql_password="Test%%*$"中的$是Bash特殊字符,会被当作变量引用,实际传递给urlencode的密码为空,导致输出的连接串缺失密码部分,同时触发Python的IndexError: list index out of range(因为sys.argv[1]不存在)。 - 不必要的URL编码:对数据库地址(如
test_pg_url.rds.amazonaws.com:5432)进行URL编码是错误的,pgloader的连接串中主机和端口无需编码,编码后会导致无法识别正确的连接地址。 - eval命令的风险:拼接命令字符串后用
eval执行,容易引发特殊字符解析错误,且存在安全隐患。
修复方案
- 用单引号包裹密码变量,避免Bash解析特殊字符;
- 仅对密码进行URL编码,主机地址和端口直接使用原始值;
- 改进URL编码函数,通过stdin传递参数,规避Bash参数解析问题;
- 直接调用pgloader命令,无需拼接字符串和eval。
修改后的脚本
#!/bin/bash # Function to URL encode a string via stdin urlencode() { python3 -c "import sys, urllib.parse as ul; print(ul.quote(sys.stdin.read().strip()))" } # MySQL connection string mysql_password='Tes^((***))' mysql_encoded_pass=$(echo "$mysql_password" | urlencode) mysql_connection="mysql://mysqluser:$mysql_encoded_pass@test_mysql_url.rds.amazonaws.com:3306/db_af" # PostgreSQL connection string pgsql_password='Test%%*$' pgsql_encoded_pass=$(echo "$pgsql_password" | urlencode) pgsql_connection="pgsql://pguser:$pgsql_encoded_pass@test_pg_url.rds.amazonaws.com:5432/db_dev" echo $pgsql_connection # Execute pgloader directly pgloader "$mysql_connection" "$pgsql_connection"
关键修改说明
- 密码变量用单引号:
mysql_password='Tes^((***))'和pgsql_password='Test%%*$',确保所有特殊字符被当作普通字符处理; - URL编码函数改进:通过stdin传递密码,避免Bash对参数的解析干扰,同时Python代码读取stdin,无需依赖sys.argv[1],防止IndexError;
- 移除地址的URL编码:直接使用原始主机地址和端口,保证pgloader能正确识别连接地址;
- 直接调用pgloader:将连接串作为参数直接传递,避免eval带来的解析问题和安全风险。
内容的提问来源于stack exchange,提问作者Prem
相关产品推荐
相关产品推荐

