120

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.

phuclv
  • 37,963
  • 15
  • 156
  • 475
hotpaw2
  • 70,107
  • 14
  • 90
  • 153

4 Answers4

176

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
Nam G VU
  • 33,193
  • 69
  • 233
  • 372
c00kiemon5ter
  • 16,994
  • 7
  • 46
  • 48
73

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:

Community
  • 1
  • 1
David Anderson
  • 1,108
  • 9
  • 17
  • 5
    This should have been the accepted answer as it proves it is indeed possible to do what the OP wants. For some even better methods in bash, this link documents the various options: http://blog.edwards-research.com/2011/05/preventing-globbing/ – geira Apr 23 '15 at 08:40
  • @geira: Sometimes an answer is accepted before a better answer is posted. I believe this may be one of those cases. I also believe the answer marks as most usefull by users ends up first. Note: I added your input to my answer. – David Anderson Apr 27 '15 at 14:11
  • @geira, the OP wants the compiled program to communicate to the shell; answering that it's possible to configure the shell to behave as desired on a command-by-command basis is a useful answer, and I myself would accept this one, but I do see room to disagree as to whether it's entirely on-point. – Charles Duffy Dec 01 '15 at 00:24
  • The fact that it *can* be done does not mean that it *should* be done. Having the shell's behavior change from the user's reasonable expectation for select commands sounds like surprising and ultimately undesirable. – tripleee Jul 29 '16 at 05:36
  • @tripleee: There was a time when people expected relays and vacuum tubes. Expected were holes punched in cardboard cards and paper tape. People held slide rules instead calculators and phones. I suppose for you this would be desirable. I did not care much for those times. I do enjoy seeing what is next. – David Anderson Jul 29 '16 at 11:31
10

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 "*"
Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
2

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']
Asclepius
  • 57,944
  • 17
  • 167
  • 143
lesnik
  • 2,507
  • 2
  • 25
  • 24