2016-10-03 118 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变量中以供调用者检索。

相关问题