31

Let's say I have a C program, and I run it from bash:

$ ./a.out 123 *

The program would output all the command line arguments, but it will show these instead:

Argument 1: 123
Argument 2: a.out

What can I do in my program to fix this?

Jay
  • 7,855
  • 4
  • 48
  • 64
Yz Chong
  • 311
  • 1
  • 3
  • 3
  • possible duplicate of http://stackoverflow.com/questions/2718873/problem-of-in-command-line-argument – polygenelubricants May 03 '10 at 02:12
  • I was a bit torn on that one, @polygene. It's certainly similar, but the other question simply seeks to understand _why_ `*` isn't working. This one wants to know if there's a way to fix it in the C code itself. My opinion (after much angst and gnashing of teeth) is that the questions are distinct enough to warrant leaving alone. – paxdiablo May 03 '10 at 02:44

5 Answers5

37

The shell is replacing the asterisk with the name of each file in the directory.

To pass a literal asterisk, you should be able to escape it:

$ ./a.out 123 \*
James McNellis
  • 327,682
  • 71
  • 882
  • 954
  • Right, I understand that that would work, but I was wondering if there is anything I could do in my C program without having to change the way I pass in arguments – Yz Chong May 03 '10 at 02:11
  • @Yz: I'm not a bash expert; my guess is that the answer is "not easily." – James McNellis May 03 '10 at 02:12
  • 8
    I _am_ a bash expert; my answer is "no!" :-) +1 for the backslash solution - this is preferred IMNSHO since the quotes will prevent variable expansion. Backslashing a single character will not have that side effect. – paxdiablo May 03 '10 at 02:20
  • 2
    You can run `bash -f` to disable globbing/filename expansion altogether, although I'm not really sure this is what the OP wants. – clstrfsck May 03 '10 at 03:16
  • 3
    James is correct. You can't do anything about this in C because the shell will replace the `*` *before* it calls your program. The C program has no way of determining whether a wildcard was passed to the shell or (in this case) a manually-typed list of files. In order to get the pure `*` to your C program, you have to escape it (that is, tell the shell not to expand it like it normally would) using `\\*`. – bta May 03 '10 at 17:37
26

Another option is to use set -f to turn off expansion. Compare:

echo *

v.s.

set -f
echo *

You can turn it back on with set +f:

set -f
echo *
set +f
echo *
Martin Tournoij
  • 23,567
  • 24
  • 90
  • 127
frankc
  • 10,603
  • 2
  • 30
  • 45
21

You can quote it in the shell

./a.out 123 '*'

There is nothing you can do in your program, because the * expansion is done by the shell (in contrast to Windows, where it's done by the program).

Matthew Flaschen
  • 255,933
  • 45
  • 489
  • 528
  • 6
    Exactly. The shell expands metacharacters BEFORE invoking the executable, so your program doesnt know that the user typed an asterisk. This is good standard Unix behaviour, and you dont want to 'fix' it. If you dont want the shell to expand metacharacters, you escape them with \ or put args inside single quotes. – leonbloy May 03 '10 at 02:47
5

Another alternative is to start your script with #!/bin/bash -f as the first line, which will allow you to accept literal strings as arguments (including the asterisk), and thus that will allow you to run ./a.out 123 * with the desired input, but note that bash -f disables expansions completely, and that can have adverse effects in your script depending on what you do.

Mahn
  • 14,870
  • 12
  • 57
  • 77
4

This doesn't have anything to do with your program.

The * is a wildcard in Bash, it means "all files in the current directory". If you want to pass an asterisk as an argument to your program, you do it the same way you do it with every other program: you escape it with a backslash or quote it.

Jörg W Mittag
  • 337,159
  • 71
  • 413
  • 614