“set -o noglob”在bash shell脚本中。

时间:2021-09-09 00:11:47

I would usually write SQL statements inline in a Bash shell script to be executed in SQLPlus as-

我通常会在Bash shell脚本中内联地编写SQL语句,以-的形式在SQLPlus中执行

#! /bin/sh

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

commit;
exit;
EOF

This would work just fine and will insert rows into dummy1 when executed. A colleague of mine came to me the other day with a script like below (simplified)

这可以很好地工作,并且在执行时将行插入dummy1。有一天,我的一个同事带着如下的脚本来找我

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

The issue with this is when executed the variable sqlvar expands the * to be all the files in the current directory and would eventually error out like-

这样做的问题是,当执行变量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

Our first stance on this one was the shell was interpreting * in a wildcard context and listing all the file names while the shell variable expansion (not quite sure why....???). So, in order to understand this we did something like below-

我们的第一个立场这个外壳是解释*通配符上下文和列出所有文件名而shell变量扩展(不知道为什么.... ? ? ?)。为了理解这个,我们做了如下的事情

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

But

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

There are a number of other files in the directory and I am not sure why * chose to execute somefile.sh or is pointed to somefile.sh.

目录中还有许多其他文件,我不确定为什么*选择执行某个文件。指某人。

After, a bit of digging we realized, using set -o noglob would resolve this issue entirely, like-

之后,我们进行了一点挖掘,使用set -o noglob来完全解决这个问题,比如-。

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

There are some conflicting or rather contradictory description of setting noglob, over the internet. So I am looking if someone could explain the knick knacks of this bit.

关于在互联网上设置noglob,有一些相互矛盾或相当矛盾的描述。所以我在寻找是否有人能解释这个小玩意儿。

2 个解决方案

#1


6  

After, a bit of digging we realized, using set -o noglob would resolve this issue entirely

之后,我们进行了一点挖掘,使用set -o noglob来彻底解决这个问题。

It doesn't resolve the issue so much as it hides it. The issue at hand is the lack of quoting. Quoting variables is usually a good practice as it prevents the shell from doing unexpected things when the variable contains special characters, whitespace, etc.

与其说它解决了问题,不如说它掩盖了问题。目前的问题是缺乏引用。引用变量通常是一个很好的实践,因为当变量包含特殊字符、空格等时,它可以防止shell执行意外的操作。

Disabling globbing does prevent the * from being expanded, but that's generally not something you want to do. It'll let you use * and ?, but things could break if you used other special characters.

禁用globbing确实会阻止*展开,但这通常不是您想要做的事情。它可以让你使用*和?,但如果你使用其他特殊字符,事情可能会破裂。

There are a number of other files in the directory and I am not sure why * chose to execute somefile.sh or is pointed to somefile.sh.

目录中还有许多其他文件,我不确定为什么*选择执行某个文件。指某人。

Here * expands to all of the file names in the current directory, and then this file list becomes the command line. The shell ends up trying to execute whichever file name is first alphabetically.

这里*扩展到当前目录中的所有文件名,然后这个文件列表成为命令行。shell最终尝试按字母顺序执行任何文件名。


So, the right way to fix this is to quote the variable:

正确的方法是引用变量

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

That will solve the wildcard problem. The other issue is that you need the \n escape sequence to be interpreted as a newline. The shell doesn't do this automatically. To get \n to work either use echo -e:

这将解决通配符问题。另一个问题是需要将\n转义序列解释为换行。shell不会自动这样做。要让\n工作,可以使用echo -e:

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

Or use the string literal syntax $'...'. That's single quotes with a dollar sign in front.

或者使用字符串文字语法$'…'。这是单引号,前面有一个美元符号。

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

(Or delete the newline.)

(或删除换行符。)

#2


3  

Before I begin: @John Kugelman's answer (appropriate quoting) is the right way to solve this problem. Setting noglob only solves some variants of the problem, and creates other potential problems in the process.

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

But since you asked what set -o noglob does, here are the relevant excerpts from the ksh man page (BTW, your tags say bash, but the error message says ksh. I presume you're actually using ksh).

但是既然您询问了set -o noglob是做什么的,下面是来自ksh man页面的相关摘录(顺便说一下,您的标记说bash,但是错误消息说ksh。我猜你是在用ksh。

noglob  Same as -f.

noglob一样- f。

-f      Disables file name generation.

-f禁止生成文件名。

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.

So what does that mean? Here's a quick example that should show the effect:

这是什么意思呢?这里有一个简单的例子可以说明这个效果:

$ 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

Now watch what changes with noglob set:

现在看看noglob集合的变化:

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

#1


6  

After, a bit of digging we realized, using set -o noglob would resolve this issue entirely

之后,我们进行了一点挖掘,使用set -o noglob来彻底解决这个问题。

It doesn't resolve the issue so much as it hides it. The issue at hand is the lack of quoting. Quoting variables is usually a good practice as it prevents the shell from doing unexpected things when the variable contains special characters, whitespace, etc.

与其说它解决了问题,不如说它掩盖了问题。目前的问题是缺乏引用。引用变量通常是一个很好的实践,因为当变量包含特殊字符、空格等时,它可以防止shell执行意外的操作。

Disabling globbing does prevent the * from being expanded, but that's generally not something you want to do. It'll let you use * and ?, but things could break if you used other special characters.

禁用globbing确实会阻止*展开,但这通常不是您想要做的事情。它可以让你使用*和?,但如果你使用其他特殊字符,事情可能会破裂。

There are a number of other files in the directory and I am not sure why * chose to execute somefile.sh or is pointed to somefile.sh.

目录中还有许多其他文件,我不确定为什么*选择执行某个文件。指某人。

Here * expands to all of the file names in the current directory, and then this file list becomes the command line. The shell ends up trying to execute whichever file name is first alphabetically.

这里*扩展到当前目录中的所有文件名,然后这个文件列表成为命令行。shell最终尝试按字母顺序执行任何文件名。


So, the right way to fix this is to quote the variable:

正确的方法是引用变量

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

That will solve the wildcard problem. The other issue is that you need the \n escape sequence to be interpreted as a newline. The shell doesn't do this automatically. To get \n to work either use echo -e:

这将解决通配符问题。另一个问题是需要将\n转义序列解释为换行。shell不会自动这样做。要让\n工作,可以使用echo -e:

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

Or use the string literal syntax $'...'. That's single quotes with a dollar sign in front.

或者使用字符串文字语法$'…'。这是单引号,前面有一个美元符号。

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

(Or delete the newline.)

(或删除换行符。)

#2


3  

Before I begin: @John Kugelman's answer (appropriate quoting) is the right way to solve this problem. Setting noglob only solves some variants of the problem, and creates other potential problems in the process.

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

But since you asked what set -o noglob does, here are the relevant excerpts from the ksh man page (BTW, your tags say bash, but the error message says ksh. I presume you're actually using ksh).

但是既然您询问了set -o noglob是做什么的,下面是来自ksh man页面的相关摘录(顺便说一下,您的标记说bash,但是错误消息说ksh。我猜你是在用ksh。

noglob  Same as -f.

noglob一样- f。

-f      Disables file name generation.

-f禁止生成文件名。

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.

So what does that mean? Here's a quick example that should show the effect:

这是什么意思呢?这里有一个简单的例子可以说明这个效果:

$ 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

Now watch what changes with noglob set:

现在看看noglob集合的变化:

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