如何在.ksh脚本中通过SQL*Plus读取客户端属性文件并传递哈希表?
先聊第一个核心问题:SQL*Plus直接读取客户端属性文件生成URL参数是否可行?
实话讲,SQLPlus原生并不擅长干这个活——它的核心定位是执行SQL/PLSQL脚本,而非处理客户端的普通文本属性文件。如果硬要在SQLPlus里实现,只能走一些绕弯子的路子:比如把属性文件改成SQL脚本格式(每行用DEFINE定义变量),再用@filename加载;或者用PLSQL的UTL_FILE包,但这个包是操作服务器端文件的,需要数据库权限,还没法直接读客户端本地文件,实用性极低。
所以你想到的先用Shell脚本读取属性文件,再把参数传递给SQL*Plus,才是日常运维里最靠谱、最灵活的方案,完全没必要硬啃SQL*Plus的短板。
再来说第二个问题:能否给SQL*Plus传递类似哈希表的结构?
首先得明确:Shell(不管是ksh还是bash)里的关联数组(也就是你说的哈希表),SQL*Plus本身是完全不认识这种数据结构的,没法直接传递。但我们可以通过转换技巧实现类似的效果,这里给你两种常用思路:
方法1:把哈希表转成键值对字符串传递,在SQL*Plus里拆分
比如在ksh里先定义哈希表:typeset -A db_props db_props["user"]="scott" db_props["pass"]="tiger" db_props["db"]="orcl"接着把它转成用分隔符(比如
|)拼接的字符串:prop_str=$(for k in "${!db_props[@]}"; do echo "$k=${db_props[$k]}"; done | tr '\n' '|')然后把这个字符串传给SQL*Plus,再用PLSQL拆分提取需要的键值:
sqlplus -s /nolog <<-EOF DEFINE prop_str = '$prop_str' DECLARE v_user VARCHAR2(100); v_pass VARCHAR2(100); v_db VARCHAR2(100); v_temp VARCHAR2(1000) := '&prop_str'; v_pos NUMBER; BEGIN -- 提取user值 v_pos := INSTR(v_temp, 'user='); IF v_pos > 0 THEN v_user := SUBSTR(v_temp, v_pos+5, INSTR(v_temp, '|', v_pos)-v_pos-5); END IF; -- 同理提取pass和db DBMS_OUTPUT.PUT_LINE('Connected User: ' || v_user); END; / EOF方法2:直接从哈希表提取单个变量传递(更推荐)
既然你已经能给SQL*Plus传Shell字符串变量,那干脆直接把哈希表里的每个键值对单独作为变量传递就行,简单又好维护:sqlplus -s "${db_props['user']}/${db_props['pass']}@${db_props['db']}" <<-EOF -- 这里如果需要用变量,直接用&user、&pass这类占位符就行 SELECT 'Connected to ' || '&db' AS status FROM dual; EOF或者如果需要先定义变量再连接,也可以这么写:
sqlplus -s /nolog <<-EOF DEFINE o_user = '${db_props['user']}' DEFINE o_pass = '${db_props['pass']}' DEFINE o_db = '${db_props['db']}' CONNECT &o_user/&o_pass@&o_db SELECT * FROM dual; EOF
总结一下
- 别折腾SQL*Plus读客户端属性文件,用Shell先解析再传递是最优解;
- 哈希表没法直接传给SQL*Plus,但转成字符串拆分、或者直接提取单个变量传递都能实现需求,后者更简单易维护。
内容的提问来源于stack exchange,提问作者AKHIL

