100
votes

Is there any way for a compiled command-line program to tell bash or csh that it does not want any wildcard characters in its parameters expanded?

For instance, one might want a shell command like:

foo *

to simply return the numeric ASCII value of that character.

4

4 Answers

133
votes

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
66
votes

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:

8
votes

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 "*"
1
votes

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']