Is there a way to make getopt() or getopt_long() recognise double character option?
example: ./a.out -my argument where my is single command.
You can use getopt_long_only, which will try to process options as long ones even if there is only one - sign before them.
This function is GNU extension, as well as getopt_long.
Related
I created a simple bash script called "myscript.h" I gave it a .h extensions for reasons that I won't disclose here. This bash script lives in "/var/ftp/something with spaces".
From the terminal, I can type in "/var/ftp/something with spaces/myscript.h" and the script works perfectly.
However, from within my C program, I type in
system("/var/ftp/something with spaces/myscript.h")
and it complains that "/var/ftp/something" is not found. I've changed my system call to the following with forward slashes:
system("/var/ftp/something\ with\ spaces/myscript.h")
However, it still complains that "/var/ftp/something" is not found. Assuming I can't change the directory names, how can I get around this?
Thanks!
To run a single script, you might avoid the system(3) library function (and use lower level system calls like fork(2), execve(2), waitpid(2)... which are used by the implementation of system(3)), or you could quote the script name when passing it to system(3).
For more details, read Advanced Linux Programming.
On Linux, system(3) is documented to fork a /bin/sh -c process. See sh(1p). And that POSIX shell has some quoting rules. You might use double-quotes and backslashes appropriately. So you would construct (and perhaps check) the string passed to system(3) (perhaps using asprintf(3) or snprintf(3) with care). Be aware that the C compiler also has (different) quoting conventions for string literals.
In general, you should avoid code injection (imagine a naughty user giving some a; rm -rf $HOME &; input as a "directory" name; you don't want to run system(3) on the weird "/var/ftp/a; rm -rf $HOME &;/myscript.h" string)
In your particular case, I recommend using fork(2), execve(2) (perhaps thru some carefully choosen exec(3) function), waitpid(2)... appropriately. This has the slight advantage to avoid depending on and running /bin/sh so could be slightly faster (by a millisecond).
Understand more the role of an Unix shell; for example, read about the various shell expansions in bash (they are similar to those mandated by POSIX sh) and be aware of globbing. See glob(7)
Note that you're adding quotes when running from the shell. You need to do the same here. Add quotes to the path name you're sending to system:
system("\"/var/ftp/something with spaces/myscript.h\"")
This should work with gcc version 5.4.0
system("\'\'/var/ftp/something\\ with\\ spaces/myscript.h\'\'");
Just put the filename inside single quotes
system("rm '/var/ftp/something with spaces/myscript.h'")
I have to restrict when the user gives "--" as an option.
For example:
./test --
should thrown an error.
For the sake of parsing I am using getopt
How to achieve this using getopt?
getopt is intended for implementing programs which conform to the POSIX Utility Syntax Guidelines where -- has a special meaning of causing all subsequent arguments to be treated as non-options even if they have the form of options (e.g. rm -- -f to remove a file named -f). There's no explicit way to suppress this behavior. You could try checking whether argv[optind-1] is "--" after getopt finishes, but this would give false positives in cases where the "--" was the argument to an option that takes an argument (something like -f -- where -f needs an argument) which you might need to work around.
If you really want argument handling that does not conform to the Utility Syntax Guidelines you might be better off rolling your own from scratch.
I'm working/developing a C program for my university, that can have 3 options when invoked (-h for help, -o <argument> (with or without it) and last option can be a string like(test-in-1):
./myprogram test-in-1
I have to process these options on my main, and do what's required when they are invoked. None of them are mandatory.
I was thinking in using getopt to parse the options however one of these options is actually a string(char *) and is with this one that I'm kinda lost since getopt is not able to read strings, only char or a char with an argument(for example,-h, -o <argument>, as far as I understood). Any idea of how can I do this?
I can't really post any code besides main line,since I'm at stuck at start of it (int main(int argc, char *argv[])).
Thanks in advance for any advice/point in right direction.
You can pass a colon : which means it requires an argument and that argument will be set in optarg.
See also my answer here
If you're linking to the GNU C library, check out getopt_long.
How to capture a parameter after some string in command line?
./executable.out -apps path_to_out
In the above code I want to store path_to_out in a string variable. What is the efficient way of doing that?
It kind of depends what kind of options you want. If you are willing to have only single-letter options, you can use the C library function getopt to parse the command line. If you would like long options (e.g., --apps), you can use getopt_long, but this is a GNU extension that will not port well. If you want really, really fancy option parsing, you can use something like GLib.
Of course, you can just roll your own, iterating over the arguments from 1 to argc and, when you encounter -apps, check that i+1 < argc and grab the next argument.
argv[argc-1] already has the value for you if your path is the last argument in the command line.
if your main is like :
int main(int argc,char **argv)
all the command line arguments are in char **argv.
in your case:
argv[2] is path_to_out.
if you want to copy it in a string,you can anyhow do this below thing:
string path(argv[2]);
It appears that by asking "after some string on the commandline" you are referring to the fact that the commandline argument -apps started with a dash, which makes it an "option".
The preferred way to doing this is to use a predefined library for processing options, such as getopt on GNU systems.
when you run parameter store in this way..
Example:---> ./executable.out -apps path_to_out
argv[0] will be "./executable.out"
argv[1] will be "-apps"
and argv[2] will be "path_to_out".
How can I accept a command line argument this way:
./a.out --printall
so that inside my program, I have something like
if (printall) {
// do something
}
I don't want to do this:
if (argc == 2)
//PRINTALL exists
since my program can have multiple command line options:
./a.out --printread
./a.out --printwrite
Secondly, I don't want to use getopt , such that the command becomes
./a.out -printall 1
I just find ./a.out --printall cleaner than ./a.out -printall 1
Edit:
I have seen programs that do this:
./a.out --help
I wonder how they work.
(About the argument parsing part of the question:)
You will need getopt_long() from <unistd.h>. This is a GNU extension.
For greater portability, you might consider Boost program options, though that's a compiled library.
Command line arguments cannot be used to trigger conditional compilation. The program has already been compiled before the program is run.
This is a very pedantic answer. For command-line options in general, see Kerrek SB's answer.