我通常会在Bash shell脚本中内联编写SQL
语句,以SQLPlus
执行 -
#! /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
互联网上对set
ting noglob
有一些相互矛盾或相当矛盾的描述。所以我在寻找是否有人可以解释这一点的诀窍。
答案 0 :(得分:8)
之后,我们意识到,使用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
(或删除换行符。)
答案 1 :(得分:4)
在开始之前:@John Kugelman的回答(适当的引用)是解决这个问题的正确方法。设置noglob只能解决问题的某些变体,并在此过程中产生其他潜在问题。
但是既然你问了set -o noglob
做了什么,这里是ksh手册页的相关摘录(BTW,你的标签说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