【问题标题】:Pipe break itteration?管道中断迭代?
【发布时间】:2019-03-23 03:37:44
【问题描述】:

我有一个很奇怪的问题,希望你的眼睛能帮助解决它。

我定义了一个函数,它通过 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
    }

上面的代码在命令行调用函数时效果很好:

[root@localhost]> NewUserSubID
SQL*Plus:11.2 版生产
版权所有 (c) 1982, 2013,甲骨文。版权所有。
连接到:
Oracle 数据库 11g 企业版 11.2 版

SQL> SQL>
MAX(SUBSCRIPTION_ID)+1
-------------------------------------
                                 1082
经过:00:00:00.00
SQL> 从 Oracle Database 11g 企业版 11.2 版断开连接


[root@localhost]> NewUserSubID
SQL*Plus:11.2 版生产
版权所有 (c) 1982, 2013,甲骨文。版权所有。
连接到:
Oracle 数据库 11g 企业版 11.2 版

SQL> SQL>
MAX(SUBSCRIPTION_ID)+2
-------------------------------------
                                 1083
经过:00:00:00.00
SQL> 从 Oracle Database 11g 企业版 11.2 版断开连接


[root@localhost]> NewUserSubID
SQL*Plus:11.2 版生产
版权所有 (c) 1982, 2013,甲骨文。版权所有。
连接到:
Oracle 数据库 11g 企业版 11.2 版

SQL> SQL>
MAX(SUBSCRIPTION_ID)+3
-------------------------------------
                                 1084
经过:00:00:00.00
SQL> 从 Oracle Database 11g 企业版 11.2 版断开连接


[root@localhost]> NewUserSubID
SQL*Plus:11.2 版生产
版权所有 (c) 1982, 2013,甲骨文。版权所有。
连接到:
Oracle 数据库 11g 企业版 11.2 版

SQL> SQL>
MAX(SUBSCRIPTION_ID)+4
-------------------------------------
                                 1085
经过:00:00:00.00
SQL> 从 Oracle Database 11g 企业版 11.2 版断开连接

但是,当函数通过管道传递到 AWK 语句中时,函数不再迭代,这是没有意义的!请参阅下面的输出:

[root@localhost] > NewUserSubID | awk 'NR==9{打印 $1}'
1086
[root@localhost] > NewUserSubID | awk 'NR==9{打印 $1}'
1086
[root@localhost] > NewUserSubID | awk 'NR==9{打印 $1}'
1086
[root@localhost] > NewUserSubID | awk 'NR==9{打印 $1}'
1086
[root@localhost] > NewUserSubID | awk 'NR==9{打印 $1}'
1086

我不明白。大声笑,我真的希望我只是忽略了一些简单的事情,但我没有想法。任何帮助都会很棒!

【问题讨论】:

    标签: oracle bash awk oracle11g


    【解决方案1】:

    问题是管道在此处用作命令的一部分:

    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
    

    【讨论】:

    • 我试过了,虽然它确实允许迭代,但它不会只删除新 ID,我仍然可以看到整个 SQL 输出,这就是我试图用 AWK 过滤掉的内容.有没有比 AWK 更好的方法?
    • 哇!那是完美的。你能给我指向一个维基或链接,我可以在其中阅读更多相关信息吗?我正在阅读有关process-substitution 的信息,但我没有看到解释需要第二个“>”的部分,为什么这一切都有效?谢谢!
    • 当我尝试将此命令分配给稍后调用的变量时遇到同样的问题.... NEW_USER=$(NewUserSubID> >(awk 'NR==9{print $1}' )) ...我知道我又陷入了同样的子壳地狱问题...但我不知道该怎么做。
    • 嗯,这将再次创建一个子外壳。让我试着调整一下。
    【解决方案2】:

    当您在不通过管道传输结果的情况下运行该函数时,它会在当前 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 变量中以供调用者检索。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-05
      • 2020-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-10
      • 2023-03-15
      相关资源
      最近更新 更多