shell編程技巧——循環邏輯中使用變量引用方式注意事項
2025-09-02 16:14 瀟湘隱者 閱讀(117) 評論(0) 收藏 舉報在shell腳本編程中,因為shell腳本的靈活多變與技巧多樣性, 我們為了腳本的健壯性,我們經常會定義一些規范,例如變量, 我們一般不用$var, 而用"$var"或"${var}"這種變量引用方式,但是往往它們之間的一些細微差別可能讓你的shell腳本產生完全意想不到的的效果. 下面我們通過一個簡單的例子來闡述一下.
函數check_invalid_obj主要的功能是在各個PDB數據庫中檢查無效對象(INVALID OBJECTS), 其中函數get_pdb_list是獲取PDB數據庫名的列表并賦值給變量$PDB_LIST
check_invalid_obj() {
get_pdb_list
# 檢查是否獲取到PDB列表
if [ -z "$PDB_LIST" ]; then
log_error "錯誤: 未能獲取到PDB列表,請檢查數據庫連接"
exit ${FAILURE}
fi
# 在每個PDB中執行SQL語句
for pdb_name in "${PDB_LIST}";
do
if [ -n "$pdb_name" ];
then
log_info "正在 $pdb_name 中執行SQL..."
# 執行SQL語句
sqlplus -S /nolog <<EOF
whenever sqlerror exit sql.sqlcode
set serveroutput on;
${CONNECT_INFO}
ALTER SESSION SET CONTAINER="$pdb_name";
set linesize 720
set pagesize 60
col object_name for a40
col object_type for a15
col owner for a10
select object_name,object_type,owner,status from dba_objects where status<>'VALID' order by owner,object_name;
exit;
EOF
fi
done
}
上面這段代碼似乎看著沒有問題,它跟下面這段代碼只有一個地方有細微的區別(循環中變量PDB_LIST的引用方式不同)
check_invalid_obj() {
get_pdb_list
# 檢查是否獲取到PDB列表
if [ -z "$PDB_LIST" ]; then
log_error "錯誤: 未能獲取到PDB列表,請檢查數據庫連接"
exit ${FAILURE}
fi
# 在每個PDB中執行SQL語句
for pdb_name in ${PDB_LIST};
do
if [ -n "$pdb_name" ];
then
log_info "正在 $pdb_name 中執行SQL..."
# 執行SQL語句
sqlplus -S /nolog <<EOF
whenever sqlerror exit sql.sqlcode
set serveroutput on;
${CONNECT_INFO}
ALTER SESSION SET CONTAINER="$pdb_name";
set linesize 720
set pagesize 60
col object_name for a40
col object_type for a15
col owner for a10
select object_name,object_type,owner,status from dba_objects where status<>'VALID' order by owner,object_name;
exit;
EOF
fi
done
}
如下截圖所示(對比著色部分)

這兩段代代碼,那一段代碼才能正常運行呢? 答案是下面這一段代碼. 也許只有你自己去調試運行一下,才會明白體會這其中的區別:
- ${PDB_LIST} 它不保留任何空白或特殊字符,而且分詞(word splitting)只發生在無引號的變量
- "${PDB_LIST}" 它會保留空白/特殊字符, 變量使用雙引號方式,會將變量的所有值視為一個整體,導致無法分詞(word splitting).
調試運行這兩段代碼,你就能體會這細微的差別了.具體如下所示(PDB數據庫有PDB1,PDB2兩個):
錯誤寫法的執行步驟詳細信息:
................................................
+ check_invalid_obj
+ get_pdb_list
++ sqlplus -S /nolog
+ PDB_LIST='PDB1
PDB2'
+ '[' -z 'PDB1
PDB2' ']'
+ for pdb_name in "${PDB_LIST}"
+ '[' -n 'PDB1
PDB2' ']'
+ log_info '正在 PDB1
PDB2 中執行SQL...'
+ '[' 1 -eq 1 ']'
+ local 'log_msg=正在 PDB1
PDB2 中執行SQL...'
+ case $LOG_OUT_TYPE in
++ date '+%Y%m%d %H:%M:%S'
+ echo -e '[info]: 20250902 14:38:27> 正在 PDB1
PDB2 中執行SQL...'
[info]: 20250902 14:38:27> 正在 PDB1
PDB2 中執行SQL...
++ date '+%Y%m%d %H:%M:%S'
+ echo -e '[info]: 20250902 14:38:27> 正在 PDB1
PDB2 中執行SQL...'
+ sqlplus -S /nolog
ALTER SESSION SET CONTAINER="PDB1
*
ERROR at line 1:
ORA-65000: missing or invalid pluggable database name
........................................................
正確寫法的執行步驟詳細信息:
+ check_invalid_obj
+ get_pdb_list
++ sqlplus -S /nolog
+ PDB_LIST='PDB1
PDB2'
+ '[' -z 'PDB1
PDB2' ']'
+ for pdb_name in ${PDB_LIST}
+ '[' -n PDB1 ']'
+ log_info '正在 PDB1 中執行SQL...'
+ '[' 1 -eq 1 ']'
+ local 'log_msg=正在 PDB1 中執行SQL...'
+ case $LOG_OUT_TYPE in
++ date '+%Y%m%d %H:%M:%S'
+ echo -e '[info]: 20250902 14:41:06> 正在 PDB1 中執行SQL...'
[info]: 20250902 14:41:06> 正在 PDB1 中執行SQL...
++ date '+%Y%m%d %H:%M:%S'
+ echo -e '[info]: 20250902 14:41:06> 正在 PDB1 中執行SQL...'
+ sqlplus -S /nolog
Session altered.
no rows selected
+ for pdb_name in ${PDB_LIST}
+ '[' -n PDB2 ']'
+ log_info '正在 PDB2 中執行SQL...'
+ '[' 1 -eq 1 ']'
+ local 'log_msg=正在 PDB2 中執行SQL...'
+ case $LOG_OUT_TYPE in
++ date '+%Y%m%d %H:%M:%S'
+ echo -e '[info]: 20250902 14:41:06> 正在 PDB2 中執行SQL...'
++ date '+%Y%m%d %H:%M:%S'
+ echo -e '[info]: 20250902 14:41:06> 正在 PDB2 中執行SQL...'
+ sqlplus -S /nolog
[info]: 20250902 14:41:06> 正在 PDB2 中執行SQL...
Session altered.
no rows selected
掃描上面二維碼關注我
如果你真心覺得文章寫得不錯,而且對你有所幫助,那就不妨幫忙“推薦"一下,您的“推薦”和”打賞“將是我最大的寫作動力!
本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接.
浙公網安備 33010602011771號