Command line arguments

B

BartC

I've just discovered that a single command line argument containing
wildcards, such as *.c, is expanded to a full list of matching files before
it gets to main().

That isn't really what I want (and there could be thousands of matching
files, which I may not want to deal with in my C program, but pass on to
something else, or the argument may not be a file specification at all).

Is there any way this behaviour can be changed, without needing to write
arguments in a special way?

(On Windows, I can choose to use the WinMain entry point instead; but this
won't work under Linux, assuming that that also expands.)
 
P

pu

I've just discovered that a single command line argument containing
wildcards, such as *.c, is expanded to a full list of matching files before
it gets to main().

That isn't really what I want (and there could be thousands of matching
files, which I may not want to deal with in my C program, but pass on to
something else, or the argument may not be a file specification at all).

Is there any way this behaviour can be changed, without needing to write
arguments in a special way?

(On Windows, I can choose to use the WinMain entry point instead; but
this won't work under Linux, assuming that that also expands.)

put the argument between quotes

===pu@pumbair:~:502=== echo *
Calibre Library Desktop Documents Downloads Dropbox Library Movies Music
Pictures Projects Public Sites Software System test

===pu@pumbair:~:503=== echo "*"
*

===pu@pumbair:~:504=== echo '*'
*
 
W

Willem

BartC wrote:
) I've just discovered that a single command line argument containing
) wildcards, such as *.c, is expanded to a full list of matching files before
) it gets to main().

It gets expanded even before the program is started, by the shell.

) That isn't really what I want (and there could be thousands of matching
) files, which I may not want to deal with in my C program, but pass on to
) something else, or the argument may not be a file specification at all).
)
) Is there any way this behaviour can be changed, without needing to write
) arguments in a special way?

No.

) (On Windows, I can choose to use the WinMain entry point instead; but this
) won't work under Linux, assuming that that also expands.)

On Windows, the main() should not get the expanded arguments either, unless
you use some kind of special C compiler that adds extra code for the
expanding.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
B

BartC

Willem said:
BartC wrote:
) I've just discovered that a single command line argument containing
) wildcards, such as *.c, is expanded to a full list of matching files
before
) it gets to main().
) (On Windows, I can choose to use the WinMain entry point instead; but
this
) won't work under Linux, assuming that that also expands.)

On Windows, the main() should not get the expanded arguments either,
unless
you use some kind of special C compiler that adds extra code for the
expanding.

I use gcc. Other compilers, I've just seen, don't do it. Presumably gcc is
anyway just mirroring the behaviour of its 'home' system.

BTW, using quotes doesn't have the effect, in Windows, that 'pu' suggested.
Not that that is too practical anyway.

However, I've just found out from somewhere that having this line somewhere
in my program:

int _CRT_glob = 0;

fixes the problem in Windows!

It sounds like it will still be a problem under Linux, and my program had
better be prepared for being potentially offered a million parameters
instead of the one or two it might expect! (Was this automatic expansion, of
something which might not even be a file-spec, ever considered a good idea
in Linux?)
 
J

Jorgen Grahn

.
It sounds like it will still be a problem under Linux, and my program had
better be prepared for being potentially offered a million parameters
instead of the one or two it might expect! (Was this automatic expansion, of
something which might not even be a file-spec, ever considered a good idea
in Linux?)

It has been considered a good idea on Unix for 40 years, and it's not
going to change. Best is if you can stop seeing it as a problem!

/Jorgen
 
G

Greg Martin

I use gcc. Other compilers, I've just seen, don't do it. Presumably gcc is
anyway just mirroring the behaviour of its 'home' system.

BTW, using quotes doesn't have the effect, in Windows, that 'pu' suggested.
Not that that is too practical anyway.

However, I've just found out from somewhere that having this line somewhere
in my program:

int _CRT_glob = 0;

fixes the problem in Windows!

It sounds like it will still be a problem under Linux, and my program had
better be prepared for being potentially offered a million parameters
instead of the one or two it might expect! (Was this automatic
expansion, of
something which might not even be a file-spec, ever considered a good idea
in Linux?)

It's a feature not a problem. It's part of the shell you are running -
I'm guessing bash? You can use the built-in set and turn it off:

set -o noglob
 
G

glen herrmannsfeldt

BartC said:
I've just discovered that a single command line argument containing
wildcards, such as *.c, is expanded to a full list of matching files before
it gets to main().
That isn't really what I want (and there could be thousands of matching
files, which I may not want to deal with in my C program, but pass on to
something else, or the argument may not be a file specification at all).
Is there any way this behaviour can be changed, without needing to write
arguments in a special way?

Not by the program.

If you use csh or tcsh, put

set noglob

into your .cshrc file.

If you use bash, you need a different command in your .bashrc,
which someone else will tell you about.
(On Windows, I can choose to use the WinMain entry point instead; but this
won't work under Linux, assuming that that also expands.)

On Windows, if it is done it is done by the C startup routines
before they call main.

In unix/Linux or any unix-like system it is done before the program
is called.

Type

echo *

as an example. (The echo command prints its arguments.)

The other way is to write your own shell.

-- glen
 
B

BartC

Greg Martin said:
On 13-01-10 01:34 PM, BartC wrote:
It's a feature not a problem.

Suppose a program expects two parameters, both of which contain wildcards.
The result will be a single list of files; how to tell where the first set
of files ends, and the next begins? Or the second parameter should be a
single file; how to tell whether that parameter was present? Etc.
It's part of the shell you are running - I'm guessing bash? You can use
the built-in set and turn it off:

set -o noglob

I've have a look later. If that works, that's good. But I can see problems:
it'll work on my system, but someone else running my program will also have
to do that set command. And it might stop other programs working properly
that expect the expansion.
 
L

Lew Pitcher

Suppose a program expects two parameters, both of which contain wildcards.
The result will be a single list of files; how to tell where the first set
of files ends, and the next begins? Or the second parameter should be a
single file; how to tell whether that parameter was present? Etc.


I've have a look later. If that works, that's good. But I can see
problems: it'll work on my system, but someone else running my program
will also have to do that set command. And it might stop other programs
working properly that expect the expansion.

Please note that you are asking for a change of behaviour in the execution
environment, that is outside of the scope of the C language. Filename
globbing (or lack of it) is not part of the C standard; if you require your
program to perform it's own globbing, then you must use some utility
(likely an API) that is outside of the C standard. Each execution
environment will have it's own unique support, or perhaps no support at
all, for program-directed globbing.

Also note that, in most environments, the behaviour that you are asking for
is governed by well-known options /in that environment/. In POSIX/SUS
environments, globbing is done by the shell, and the facilities to disable
globbing are well known (set -o noglob, or even singlequoting the
argument).

You are trying to address a human-factors problem ("how to know to turn off
globbing when using this program") with code; never a good idea.

Here's the best advice:

** DOCUMENT THE REQUIREMENT IN THE OPERATING INSTRUCTIONS **

Wasn't that simple?

HTH
 
F

Fred K

"Greg Martin" <[email protected]> wrote in message news:[email protected]... > On 13-01-10 01:34 PM, BartC wrote: >> It sounds like it will still be a problem under Linux > It's a feature not a problem. Suppose a program expects two parameters, both of which contain wildcards. The result will be a single list of files; how to tell where the first set of files ends, and the next begins? Or the second parameter should be a single file; how to tell whether that parameter was present? Etc. > It's part of the shell you are running - I'm guessing bash? You can use > the built-in setand turn it off: > > set -o noglob I've have a look later. If that works, that's good. But I can see problems: it'll work on my system, but someone else running my program will also have to do that set command. And it might stop other programs working properly that expect the expansion. -- Bartc

As others have said, it isw the shell that is doing this, not your program.
Users must be aware of the shell they are using, and use it appropriately.

If you want your program to receive two parameters containing wildcards
such as
a*b
cc*d

then execute the program properly:
myProgram 'a*b' 'cc*d'
 
B

BruceS

Please note that you are asking for a change of behaviour in the execution
environment, that is outside of the scope of the C language. Filename
globbing (or lack of it) is not part of the C standard; if you require your
program to perform it's own globbing, then you must use some utility
(likely an API) that is outside of the C standard. Each execution
environment will have it's own unique support, or perhaps no support at
all, for program-directed globbing.

Lew beat me to it. From a terminal (in Linux), type 'echo *', and it
echos a list of the files in that directory. Enclose in quotes (as
suggested elsethread), and type 'echo "*"', and get a single asterix.
If, as Greg suggested, I type 'set -o noglog', then type 'echo *', I get
the single asterix. The globbing is being done by the OS, before your
program gets run. Bart, I don't know if noglob works in all shells, but
that sounds like your best bet for the Linux side, as you say using
enclosing quotes isn't practical.
Also note that, in most environments, the behaviour that you are asking for
is governed by well-known options /in that environment/. In POSIX/SUS
environments, globbing is done by the shell, and the facilities to disable
globbing are well known (set -o noglob, or even singlequoting the
argument).

You are trying to address a human-factors problem ("how to know to turn off
globbing when using this program") with code; never a good idea.

Here's the best advice:

** DOCUMENT THE REQUIREMENT IN THE OPERATING INSTRUCTIONS **

Wasn't that simple?

HTH

Thanks, Lew. I may never have a need for noglob, but I didn't know
about it before.
 
S

Shao Miller

I've just discovered that a single command line argument containing
wildcards, such as *.c, is expanded to a full list of matching files before
it gets to main().

That isn't really what I want (and there could be thousands of matching
files, which I may not want to deal with in my C program, but pass on to
something else, or the argument may not be a file specification at all).

Is there any way this behaviour can be changed, without needing to write
arguments in a special way?

(On Windows, I can choose to use the WinMain entry point instead; but
this won't work under Linux, assuming that that also expands.)

I usually escape the asterisk:

./prog \*.ext
 
L

Lew Pitcher

On 01/10/2013 03:49 PM, Lew Pitcher wrote: [snip]
Also note that, in most environments, the behaviour that you are asking
for is governed by well-known options /in that environment/. In POSIX/SUS
environments, globbing is done by the shell, and the facilities to
disable globbing are well known (set -o noglob, or even singlequoting the
argument).

You are trying to address a human-factors problem ("how to know to turn
off globbing when using this program") with code; never a good idea.

Here's the best advice:

** DOCUMENT THE REQUIREMENT IN THE OPERATING INSTRUCTIONS **

Wasn't that simple?

Thanks, Lew. I may never have a need for noglob, but I didn't know
about it before.

You're welcome, BruceS

I can't claim the "-o noglob" option idea as my own, and others also know of
the quoting solution, but thanks for the kudos anyway ;-)

As for my real advice, the OP should read the manpage for the Unix find(1)
command, specifically where it addresses the -name option. find(1) performs
it's own globbing internally, and the manpage makes special note of it

To quote:
-name pattern
Base of file name (the path with the leading directories
removed) matches shell pattern pattern. The metacharacters
(`*', `?', and `[]') match a `.' at the start of the base name
(this is a change in findutils-4.2.2; see section STANDARDS CON-
FORMANCE below). To ignore a directory and the files under it,
use -prune; see an example in the description of -wholename.
Braces are not recognised as being special, despite the fact
that some shells including Bash imbue braces with a special
meaning in shell patterns. The filename matching is performed
with the use of the fnmatch(3) library function. Don't forget
to enclose the pattern in quotes in order to protect it from
expansion by the shell.

Note that last line in the documentation:
"Don't forget to enclose the pattern in quotes in order to protect it
from expansion by the shell."

That's how you solve that particular human-factors problem.
 
K

Keith Thompson

BartC said:
I've just discovered that a single command line argument containing
wildcards, such as *.c, is expanded to a full list of matching files before
it gets to main().

That's specific to your operating system and the environment in which
you invoke the program.
That isn't really what I want (and there could be thousands of matching
files, which I may not want to deal with in my C program, but pass on to
something else, or the argument may not be a file specification at all).

Is there any way this behaviour can be changed, without needing to write
arguments in a special way?

(On Windows, I can choose to use the WinMain entry point instead; but this
won't work under Linux, assuming that that also expands.)

On Unix-like systems, that's just how the shell works. If you want to
pass a literal '*' to your program, you need to quote it; you can use
single or double quotes, or escape it with a leading backslash: \*.

Consider carefully whether you really want to do this. Almost all Unix
programs *expect* to see expanded command-line arguments, and wouldn't
know what to do with a wildcard. (There are a few exceptions, like the
"find" command.) Avoid violating user expectations unless you really
need to.

You won't be able to pass a literal "*" to your program without quoting
it unless you write your own shell or equivalent.
 
G

glen herrmannsfeldt

Suppose a program expects two parameters, both of which contain wildcards.

No program do that. Now you know why.
The result will be a single list of files; how to tell where the first set
of files ends, and the next begins? Or the second parameter should be a
single file; how to tell whether that parameter was present? Etc.

There are cases where files can be lost due to misusing file expansion.

Users of some other systems sometimes try

mv abc.* xyz.*

If there are two files starting with abc., the first will replace
the second. Don't do that.

Now, there is another form of mv that takes a list of files and one
directory. It will only work if the last one in the list is a directory,
though.
I've have a look later. If that works, that's good. But I can see problems:
it'll work on my system, but someone else running my program will also have
to do that set command. And it might stop other programs working properly
that expect the expansion.

No programs expect the expansion, users do.

If you type

rm *.c

the rm command gets a list of files, which it deletes. With noglob, it
will (try to) delete a file named *.c, most likely one doesn't exist.

Normally, you either quote the file, or list of files, that you don't
want expanded, or escape with \ the * or ? you don't want expanded.

rm \*.c

will delete a file named *.c, instead of all .c files.

-- glen
 
J

Joe Pfeiffer

BartC said:
I've just discovered that a single command line argument containing
wildcards, such as *.c, is expanded to a full list of matching files before
it gets to main().

That isn't really what I want (and there could be thousands of matching
files, which I may not want to deal with in my C program, but pass on to
something else, or the argument may not be a file specification at all).

Is there any way this behaviour can be changed, without needing to write
arguments in a special way?

(On Windows, I can choose to use the WinMain entry point instead; but
this won't work under Linux, assuming that that also expands.)

The real problem isn't affected by the presence or absence of file
"globbing" -- it's that you have to check that the input is valid.

To take an absurd example, somebody running your program from a command
interpreter under Windows could go through and type the name of each
file individually on the command line. This would present you with
exactly the same problem. In general any wrong input that can be
produced as a result of file globbing can equally be produced by a
careless (or ignorant, or malicious) user.

If your program wants exactly two (or whatever the right number is)
arguments, you need to make sure the user gave you two arguments. I've
written many, many programs whose main() starts like this:

if ((argc < 2) || (argc > 3) ||
((argc == 3) && (argv[1][0] != '-')))
usage();

where usage() is a function that prints a synopsis of the expected
command line arguments, and then calls exit(1).

(this example will make sure that I passed in at least one argument, and
if I passed in two then the first one needs to start with a hyphen)

If you actually want '*' as a valid character in a command line argument
expected by your program, your best bet is to reconsider your choices of
valid command line arguments. Other than that, you'll just have to hope
that your program's users are familiar with the conventions of the Unix
command line.
 
J

James Kuyper

On 01/10/2013 04:34 PM, BartC wrote:
....
It sounds like it will still be a problem under Linux, and my program had
better be prepared for being potentially offered a million parameters
instead of the one or two it might expect! (Was this automatic expansion, of
something which might not even be a file-spec, ever considered a good idea
in Linux?)

Yes, because it's trivial to prevent wild card expansion, if you don't
need it, by using double quotes. I use wild card expansions constantly
while working on Unix-like machines, and I've found them extremely
useful. When I was writing code, several decades ago, to run on a DOS
platform using the Command Line Interpreter, I had to use DOS utilities
to emulate the same behavior that occurred automatically under unix
shells. I found it quite annoying.
 
S

Shao Miller

On 01/10/2013 04:34 PM, BartC wrote:
...

Yes, because it's trivial to prevent wild card expansion, if you don't
need it, by using double quotes. I use wild card expansions constantly
while working on Unix-like machines, and I've found them extremely
useful. When I was writing code, several decades ago, to run on a DOS
platform using the Command Line Interpreter, I had to use DOS utilities
to emulate the same behavior that occurred automatically under unix
shells. I found it quite annoying.

And that's why, if you compile a POSIX- or UNIX-style program for
Windows, it'll usually include a startup routine to reproduce this
behaviour, since you can invoke your POSIX- or UNIX-style program from a
CLI/shell that _doesn't_ do this command-line expansion before passing
it on to the program.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top