阻止外壳通配符膨胀?

编译后的命令行程序有没有办法告诉 bash 或 csh 它不希望在其参数中扩展任何通配符?

例如,您可能需要一个 shell 命令,比如:

foo *

简单地返回该字符的数字 ASCII 值。

80138 次浏览

The expansion is performed by the shell before your program is run. Your program has no clue as to whether expansion has occurred or not.

   set -o noglob

will switch off expansion in the invoking shell, but you'd have to do that before you invoke your program.

The alternative is to quote your arguments e.g.

foo "*"

No. The expansion takes place before the command is actually run.
You can only disable the glob before running the command or by quoting the star.

$ # quote it
$ foo '*'


$ # or escape it
$ foo \*


$ # or disable the glob (noglob)
$ set -f
$ foo *


$ # alternative to set -f
$ set -o noglob
$ # undo it by
$ set +o noglob

While it is true a command itself can not turn off globbing, it is possible for a user to tell a Unix shell not to glob a particular command. This is usually accomplished by editing a shell's configuration files. Assuming the command foo can be found along the command path, the following would need to be added to the appropriate configuration file:

For the sh, bash and ksh shells:

alias foo='set -f;foo';foo(){ command foo "$@";set +f;}

For the csh and tcsh shells:

alias foo 'set noglob;\foo \!*;unset noglob'

For the zsh shell:

alias foo='noglob foo'

The command path does not have to be used. Say the command foo is stored in the directory ~/bin, then the above would become:

For the sh, bash and ksh shells:

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

For the csh and tcsh shells:

alias foo 'set noglob;$home/bin/foo \!*;unset noglob'

For the zsh shell:

alias foo='noglob ~/bin/foo'

All of the above was tested using Apple's OSX 10.9.2. Note: When copying the above code, be careful about deleting any spaces. They may be significant.

Update:

User geira has pointed out that in the case of a bash shell

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

could be replaced with

reset_expansion(){ CMD="$1";shift;$CMD "$@";set +f;}
alias foo='set -f;reset_expansion ~/bin/foo'

which eliminates the need for the function foo.

Some web sites used to create this document:

Beware: if there are no names matching the mask, bash passes the argument as-is, without expansion!

Proof (pa.py is a very simple script, which just prints its arguments):

 $ ls
f1.cc  f2.cc  pa.py
$ ./pa.py *.cc
['./pa.py', 'f1.cc', 'f2.cc']
$ ./pa.py *.cpp
['./pa.py', '*.cpp']