2016-10-03 114 views
3

我有一個很奇怪的問題,我希望你的眼睛可以幫助解決它。管道破損?

我有一個定義的函數,它通過BASH連接到Oracle SQL數據庫。一旦連接,我使用HEREDOC傳遞一個簡單的select語句,該語句找到一個最大訂閱ID並遞增它,具體取決於該函數被調用的次數。下面是代碼:

#!/bin/bash 
    PASS=0 
    function NewUserSubID(){ 
    PASS=$(($PASS+1)) 
    sqlplus "${DB_USER}"/"${DB_PASS}" <<EOF 
    set echo on timing on lines 200 pages 100 
    select max(SUBSCRIPTION_ID)+${PASS} from ${DB_ENV}.USER_DATA; 
    EOF 
    } 

上面的代碼的偉大工程,當函數被調用的命令行:

[[email protected]]> NewUserSubID 
SQL*Plus: Release 11.2 Production 
Copyright (c) 1982, 2013, Oracle. All rights reserved. 
Connected to: 
Oracle Database 11g Enterprise Edition Release 11.2 

SQL> SQL> 
MAX(SUBSCRIPTION_ID)+1 
------------------------------------- 
           1082 
Elapsed: 00:00:00.00 
SQL> Disconnected from Oracle Database 11g Enterprise Edition Release 11.2 


[[email protected]]> NewUserSubID 
SQL*Plus: Release 11.2 Production 
Copyright (c) 1982, 2013, Oracle. All rights reserved. 
Connected to: 
Oracle Database 11g Enterprise Edition Release 11.2 

SQL> SQL> 
MAX(SUBSCRIPTION_ID)+2 
------------------------------------- 
           1083 
Elapsed: 00:00:00.00 
SQL> Disconnected from Oracle Database 11g Enterprise Edition Release 11.2 


[[email protected]]> NewUserSubID 
SQL*Plus: Release 11.2 Production 
Copyright (c) 1982, 2013, Oracle. All rights reserved. 
Connected to: 
Oracle Database 11g Enterprise Edition Release 11.2 

SQL> SQL> 
MAX(SUBSCRIPTION_ID)+3 
------------------------------------- 
           1084 
Elapsed: 00:00:00.00 
SQL> Disconnected from Oracle Database 11g Enterprise Edition Release 11.2 


[[email protected]]> NewUserSubID 
SQL*Plus: Release 11.2 Production 
Copyright (c) 1982, 2013, Oracle. All rights reserved. 
Connected to: 
Oracle Database 11g Enterprise Edition Release 11.2 

SQL> SQL> 
MAX(SUBSCRIPTION_ID)+4 
------------------------------------- 
           1085 
Elapsed: 00:00:00.00 
SQL> Disconnected from Oracle Database 11g Enterprise Edition Release 11.2 

然而,當函數通過管道被輸送到一個AWK語句,函數不再旅行,這是沒有道理的!看到下面的輸出:

[[email protected]] > NewUserSubID | awk 'NR==9{print $1}' 
1086 
[[email protected]] > NewUserSubID | awk 'NR==9{print $1}' 
1086 
[[email protected]] > NewUserSubID | awk 'NR==9{print $1}' 
1086 
[[email protected]] > NewUserSubID | awk 'NR==9{print $1}' 
1086 
[[email protected]] > NewUserSubID | awk 'NR==9{print $1}' 
1086 

我不明白。大聲笑,我真的希望我只是俯視簡單的東西,但我沒有想法。任何幫助都是極好的!

回答

2

問題是管道作爲部分的你指揮的位置:

NewUserSubID | awk 'NR==9{print $1}' 

因爲管道創建一個子shell因此改變使得在子shell都不會反映在父shell的任何變量。

您可以使用進程替換,以避免此子shell:

$> NewUserSubID> >(awk 'NR==9{print $1}') 
1086 

$> NewUserSubID> >(awk 'NR==9{print $1}') 
1087 

$> NewUserSubID> >(awk 'NR==9{print $1}') 
1088 
+0

我嘗試這樣做,雖然它確實允許itteration,它不切出只是新的ID,我還看到了整個SQL輸出,這正是我試圖用AWK過濾出來的東西。有沒有比AWK更好的方法? – misteralexander

+0

我有一個固定的錯字。試試我更新的答案。 – anubhava

+0

哇!那很完美。你能指點我一個wiki或一個鏈接,我可以閱讀更多關於這個?我正在閱讀[過程替代](http://tldp.org/LDP/abs/html/process-sub.html),但我沒有看到解釋第二個「>」需求的部分,以及爲什麼這使所有的工作?謝謝! – misteralexander

1

當您不通過管道傳輸結果而運行該函數時,它將在當前shell中運行。但是,在運行管道時,管道中的每個命令都在其自己的子shell中運行。除此之外,這意味着這些命令不能直接影響啓動管道的shell環境。 PASS變量在每個子shell中增加,但該變化未反映在父shell中,因此每個子shell都會爲該變量查看相同的初始值。

您可以在同一個shell中執行所有操作,也可以將PASS作爲函數參數傳遞,並在外部管理增量。例如,

#!/bin/bash 

PASS=0 

NewUserSubID() { 
sqlplus "${DB_USER}"/"${DB_PASS}" <<EOF 
set echo on timing on lines 200 pages 100 
select max(SUBSCRIPTION_ID)+${1} from ${DB_ENV}.USER_DATA; 
EOF 
} 

# Use this instead of calling NewUserSubID directly: 
NewUserSubID_Print() { 
NewUserSubID $PASS | awk 'NR==9{print $1}' 
PASS=$(($PASS+1)) 
} 

謹防試圖捕捉的NewUserSubID_Print()輸出,然而,這將導致在一個子shell中運行。如果你想捕獲輸出,那麼有NewUserSubID_Print()自己做,並將其存儲在一個shell變量中以供調用者檢索。

相關問題