You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shell脚本While循环中执行Oracle数据库INSERT语句仅运行一次的问题排查与解决

解决Shell脚本While循环调用Oracle SQLcl仅执行一次的问题

我一眼就看出问题所在了——你的sql命令(SQLcl)会抢占while read循环的标准输入!

问题根源

当你用while read -r line done < $reference_file时,整个循环的输入来自$reference_file。但每次调用sql命令时,SQLcl默认会从**标准输入(stdin)**读取交互输入,这就会把$reference_file里剩下的所有行都当作自己的输入吃掉。第一次循环执行完sql后,文件里剩下的2行已经被SQLcl读走了,while read自然没有内容可以继续循环,直接退出。

核心解决方案

让sql命令不要读取原来的标准输入,最简单的方法就是把它的输入重定向到/dev/null,这样它就不会干扰while循环的输入流了。

修改你的runScript函数里的sql命令行,加上< /dev/null即可:

runScript() {
 sql ${USER}/\"${PASS}\"@${DB_INSTANCE} @temp.sql $1 $2 $3 $4 < /dev/null
 if [[ $? -ne 0 ]]; then echo "Error"; exit 2; fi
}

完整修改后的脚本

#!/bin/sh
ODATE=${1}
file_deliver_time="20210218:12:56:76"
reference_file=/var/tmp/Sneha/SSM_KPI_source_file_checklist.txt
HOME_DIR="/var/tmp/Sneha"
source ~/env/INFORMATICA.env
source ${HOME_DIR}/db.properties
runScript() {
 sql ${USER}/\"${PASS}\"@${DB_INSTANCE} @temp.sql $1 $2 $3 $4 < /dev/null
 if [[ $? -ne 0 ]]; then echo "Error"; exit 2; fi
}
cd ${HOME_DIR}
while read -r line
do
 echo $line
 if [[ -f ${HOME_DIR}/temp.sql ]]; then rm -f ${HOME_DIR}/temp.sql; fi
 echo "whenever sqlerror exit failure;" > temp.sql
 echo "set define on echo on" >> temp.sql
 echo "INSERT INTO test_ssm_kpi (source_system,file_name,delivery_timestamp,ODATE) VALUES ('&1' , '&2' , '&3' , '&4');" >> temp.sql
 echo "exit;" >> temp.sql
 file_path=$(echo $line | awk -F ';' '{print $1}' | xargs echo -n )
 file_str=$(echo $line | awk -F ';' '{print $2}' | xargs echo -n )
 file_type=$(echo $line | awk -F ';' '{print $3}' | xargs echo -n )
 file_source_sys=$(echo $line | awk -F ';' '{print $4}' | xargs echo -n )
 echo "runScript ${file_path} ${file_str} ${file_type} ${file_source_sys}"
 runScript ${file_source_sys} ${file_str} ${file_type} ${ODATE}
done < $reference_file

额外优化建议(可选)

为了让脚本更简洁高效,你还可以做以下调整:

  1. 用Here Document一次性生成temp.sql,替代多次echo操作:
cat > temp.sql <<EOF
whenever sqlerror exit failure;
set define on echo on
INSERT INTO test_ssm_kpi (source_system,file_name,delivery_timestamp,ODATE) VALUES ('&1' , '&2' , '&3' , '&4');
exit;
EOF
  1. 用IFS分割行内容,替代多次awk调用:
# 用分号作为分隔符,直接读取所有字段
IFS=';' read -r file_path file_str file_type file_source_sys <<< "$line"
# 去除字段首尾空格(如果有)
file_path=$(xargs echo -n <<< "$file_path")
file_str=$(xargs echo -n <<< "$file_str")
file_type=$(xargs echo -n <<< "$file_type")
file_source_sys=$(xargs echo -n <<< "$file_source_sys")

调整后的循环部分会更简洁,运行效率也更高。

内容的提问来源于stack exchange,提问作者Sneha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 00:37:35