【问题标题】:"set -o noglob" in bash shell scriptbash shell 脚本中的“set -o noglob”
【发布时间】:2012-09-01 05:42:58
【问题描述】:

我通常会在 Bash shell 脚本中内联编写 SQL 语句,以便在 SQLPlus as-中执行-

#! /bin/sh

sqlplus user/pwd@dbname<<EOF
insert into dummy1 
select * from dummy2;

commit;
exit;
EOF

这可以正常工作,并在执行时将行插入dummy1。前几天我的一位同事带着如下脚本来找我(简化)

#! /bin/sh    
sqlvar="insert into dummy1 select * from dummy2;commit;"    
echo $sqlvar|sqlplus user/pwd@dbname

这个问题是在执行时变量sqlvar* 扩展为当前目录中的所有文件,最终会出错-

SQL> insert into dummy1 select <--all the file names in the current directory--> 
from dummy2;commit
                                                    *
ERROR at line 1:
ORA-00923: FROM keyword not found where expected

我们对此的第一个立场是 shell 在通配符上下文中解释 * 并在 shell 变量扩展时列出所有文件名(不太清楚为什么......???)。所以,为了理解这一点,我们做了如下的事情-

$ var="hello *"
$ echo $var
hello <--all the file names in the current directory-->

但是

$*
ksh: somefile.sh: 0403-006 Execute permission denied. #since it had no execute permission

目录中还有许多其他文件,我不知道为什么* 选择执行somefile.sh 或指向somefile.sh

经过一番挖掘,我们意识到,使用set -o noglob 可以完全解决这个问题,比如-

#! /bin/sh
set -o noglob
sqlvar="insert into dummy1 select * from dummy2;\n commit;"    
echo $sqlvar|sqlplus user/pwd@dbname

在互联网上有一些对setting noglob 的相互矛盾或相当矛盾的描述。所以我正在寻找是否有人可以解释这一点的诀窍。

【问题讨论】:

    标签: bash shell inline sqlplus


    【解决方案1】:

    经过一番挖掘,我们意识到,使用 set -o noglob 可以完全解决这个问题

    它并没有解决问题,而是隐藏了它。手头的问题是缺乏引用。引用变量通常是一种很好的做法,因为当变量包含特殊字符、空格等时,它可以防止 shell 做出意外的事情。

    禁用通配确实会阻止 * 被扩展,但这通常不是您想要做的事情。它可以让您使用*?,但如果您使用其他特殊字符,事情可能会中断。

    目录中有许多其他文件,我不确定为什么 * 选择执行 somefile.sh 或指向 somefile.sh。

    这里*展开为当前目录下的所有文件名,然后这个文件列表就变成了命令行。 shell 最终会尝试按字母顺序执行第一个文件名。


    所以,解决这个问题的正确方法是引用变量:

    echo "$sqlvar" | sqlplus user/pwd@dbname
    

    这将解决通配符问题。另一个问题是您需要将\n 转义序列解释为换行符。 Shell 不会自动执行此操作。要让\n 工作,请使用echo -e

    echo -e "$sqlvar" | sqlplus user/pwd@dbname
    

    或者使用字符串文字语法$'...'。那是前面带美元符号的单引号。

    sqlvar=$'insert into dummy1 select * from dummy2;\n commit;'
    echo "$sqlvar" | sqlplus user/pwd@dbname
    

    (或删除换行符。)

    【讨论】:

    • 谢谢,但我们正在寻找设置noglob 的意义(这显然也解决了问题)。新行 char wan't there 那是我在问题中解决的错误。
    【解决方案2】:

    在我开始之前:@John Kugelman 的回答(适当引用)是解决这个问题的正确方法。设置 noglob 只能解决问题的某些变体,并在此过程中产生其他潜在问题。

    但既然你问set -o noglob 做了什么,这里是 ksh 手册页的相关摘录(顺便说一句,你的标签说 bash,但错误消息说 ksh。我想你实际上是在使用 ksh)。

    noglob  Same as -f.

    -f      Disables file name generation.

    File Name Generation.
       Following splitting, each field is scanned for the characters *, ?,  (,
       and  [  unless  the -f option has been set.  If one of these characters
       appears, then the word is regarded as a pattern.  Each file name compo-
       nent  that  contains  any  pattern character is replaced with a lexico-
       graphically sorted set of names that  matches  the  pattern  from  that
       directory.
    

    那是什么意思?这是一个应该显示效果的快速示例:

    $ echo *
    file1 file2 file3 file4
    $ ls *
    file1 file2 file3 file4
    $ *    # Note that this is equivalent to typing "file1 file2 file3 file4" as a command -- file1 is treated as the command (which doesn't exist), the rest as arguments to it
    ksh: file1: not found
    

    现在看看 noglob 集合有什么变化:

    $ set -o noglob
    $ echo *
    *
    $ ls *
    ls: *: No such file or directory
    $ *
    ksh: *: not found
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-23
      • 2013-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多