Whenever you execute a program on a terminal, you can pass some arguments that are expected by the program, which can be used during the execution of the program. Here, system provides internal facility to maintain all arguments passed from user while executing program. These arguments are known as “Command line arguments”.
In this tutorial, we will map the understanding of command line arguments with working program to understand it better in crisp and clear way. But before jumping to program, we should know how system provides facility of command line arguments. As we know, Every C program must have main() function and the facility of command line arguments is provided by the main() function itself. When given below declaration is used in program, and then program has facility to use/manipulate command line arguments.
int main (int argc, char *argv[])
Here, argc parameter is the count of total command line arguments passed to executable on execution (including name of executable as first argument). argv parameter is the array of character string of each command line argument passed to executable on execution. If you are new to C programming, you should first understand how C array works.
Given below is the working program using command line argument.
#include <stdio.h> int main (int argc, char *argv[]) { int i=0; printf("\ncmdline args count=%s", argc); /* First argument is executable name only */ printf("\nexe name=%s", argv[0]); for (i=1; i< argc; i++) { printf("\narg%d=%s", i, argv[i]); } printf("\n"); return 0; }
Given below is output when program is executed.
$ ./cmdline_basic test1 test2 test3 test4 1234 56789 cmdline args count=7 exe name=./cmdline_basic arg1=test1 arg2=test2 arg3=test3 arg4=test4 arg5=1234 arg6=56789
In above output, we can see total arguments count is internally maintained by “argc” parameter of main() which holds value ‘7’ (in which one argument is executable name and ‘6’ are arguments passed to program).And, all argument values are stored in “argv” parameter of main() which is array of character strings. Here, main () function stores each argument value as character string. We can see, iterating over “argv” array, we can get all passed arguments in the program.
There is one more declaration of main () function that provides added facility to work on environment variables inside program. Like, arguments maintained in argv[] array, main() function has internal facility to maintain all system environment variables into array of character strings which can be taken as an main() function parameter. Given below is the declaration.
int main (int argc, char *argv[], char **envp)
Given below is the working program using command line argument along with environment variables.
#include <stdio.h> int main (int argc, char *argv[], char **env_var_ptr) { int i=0; printf("\ncmdline args count=%d", argc); /* First argument is executable name only */ printf("\nexe name=%s", argv[0]); for (i=1; i< argc; i++) { printf("\narg%d=%s", i, argv[i]); } i=0; while (*env_var_ptr != NULL) { i++; printf ("\nenv var%d=>%s",i, *(env_var_ptr++)); } printf("\n"); return 0; }
Output of above program is given below.
$ ./env test1 test2 cmdline args count=3 exe name=./env arg1=test1 arg2=test2 env var1=>SSH_AGENT_PID=1575 env var2=>KDE_MULTIHEAD=false env var3=>SHELL=/bin/bash env var4=>TERM=xterm env var5=>XDG_SESSION_COOKIE=5edf27907e97deafc70d310550995c84-1352614770.691861-1384749481 env var6=>GTK2_RC_FILES=/etc/gtk-2.0/gtkrc:/home/sitaram/.gtkrc-2.0:/home/sitaram/.kde/share/config/gtkrc-2.0 env var7=>KONSOLE_DBUS_SERVICE=:1.76 env var8=>KONSOLE_PROFILE_NAME=Shell env var9=>GS_LIB=/home/sitaram/.fonts env var10=>GTK_RC_FILES=/etc/gtk/gtkrc:/home/sitaram/.gtkrc:/home/sitaram/.kde/share/config/gtkrc env var11=>WINDOWID=29360154 env var12=>GNOME_KEYRING_CONTROL=/run/user/sitaram/keyring-2Qx7DW env var13=>SHELL_SESSION_ID=f7ac2d9459c74000b6fd9b2df1d48da4 env var14=>GTK_MODULES=overlay-scrollbar env var15=>KDE_FULL_SESSION=true env var16=>http_proxy=http://10.0.0.17:8080/ env var17=>USER=sitaram env var18=>LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36: env var19=>XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0 env var20=>XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0 env var21=>SSH_AUTH_SOCK=/tmp/ssh-kIFY5HttOJxe/agent.1489 env var22=>ftp_proxy=ftp://10.0.0.17:8080/ env var23=>SESSION_MANAGER=local/Sitaram:@/tmp/.ICE-unix/1716,unix/Sitaram:/tmp/.ICE-unix/1716 env var24=>DEFAULTS_PATH=/usr/share/gconf/kde-plasma.default.path env var25=>XDG_CONFIG_DIRS=/etc/xdg/xdg-kde-plasma:/etc/xdg env var26=>DESKTOP_SESSION=kde-plasma env var27=>PATH=/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games env var28=>PWD=/home/sitaram/test_progs/cmdline env var29=>socks_proxy=socks://10.0.0.17:8080/ env var30=>KONSOLE_DBUS_WINDOW=/Windows/1 env var31=>KDE_SESSION_UID=1000 env var32=>LANG=en_IN env var33=>GNOME_KEYRING_PID=1478 env var34=>MANDATORY_PATH=/usr/share/gconf/kde-plasma.mandatory.path env var35=>UBUNTU_MENUPROXY=libappmenu.so env var36=>KONSOLE_DBUS_SESSION=/Sessions/1 env var37=>https_proxy=https://10.0.0.17:8080/ env var38=>GDMSESSION=kde-plasma env var39=>SHLVL=1 env var40=>HOME=/home/sitaram env var41=>COLORFGBG=15;0 env var42=>KDE_SESSION_VERSION=4 env var43=>LANGUAGE=en_IN:en env var44=>XCURSOR_THEME=Oxygen_White env var45=>LOGNAME=sitaram env var46=>XDG_DATA_DIRS=/usr/share/kde-plasma:/usr/local/share/:/usr/share/ env var47=>DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-mnJhMvd4jG,guid=435ddd41500fd6c5550ed8d2509f4374 env var48=>LESSOPEN=| /usr/bin/lesspipe %s env var49=>PROFILEHOME= env var50=>XDG_RUNTIME_DIR=/run/user/sitaram env var51=>DISPLAY=:0 env var52=>QT_PLUGIN_PATH=/home/sitaram/.kde/lib/kde4/plugins/:/usr/lib/kde4/plugins/ env var53=>LESSCLOSE=/usr/bin/lesspipe %s %s env var54=>XAUTHORITY=/tmp/kde-sitaram/xauth-1000-_0 env var55=>_=./env env var56=>OLDPWD=/home/sitaram/test_progs $
In above output, we can see all system environment variables can be obtained third parameter of main() function which are traversed in program and displayed in output.
Passing command line arguments to program and manipulate arguments
Given below is program working on command line arguments.
#include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { int i=0; int d; float f; long int l; FILE *file = NULL; printf("\ncmdline args count=%d", argc); /* First argument is executable name only */ printf("\nexe name=%s", argv[0]); for (i=1; i< argc; i++) { printf("\narg%d=%s", i, argv[i]); } /* Conversion string into int */ d = atoi(argv[1]); printf("\nargv[1] in intger=%d",d); /* Conversion string into float */ f = atof(argv[1]); printf("\nargv[1] in float=%f",f); /* Conversion string into long int */ l = strtol(argv[2], NULL, 0); printf("\nargv[2] in long int=%ld",l); /*Open file whose path is passed as an argument */ file = fopen( argv[3], "r" ); /* fopen returns NULL pointer on failure */ if ( file == NULL) { printf("\nCould not open file"); } else { printf("\nFile (%s) opened", argv[3]); /* Closing file */ fclose(file); } printf("\n"); return 0; }
Output of above program is given below.
$ ./cmdline_strfunc 1234test 12345678 /home/sitaram/test_progs/cmdline/cmdline_strfunc.c cmdline args count=4 exe name=./cmdline_strfunc arg1=1234test arg2=12345678 arg3=/home/sitaram/test_progs/cmdline/cmdline_strfunc.c argv[1] in intger=1234 argv[1] in float=1234.000000 argv[2] in long int=12345678 File (/home/sitaram/test_progs/cmdline/cmdline_strfunc.c) opened
In above output, we can see that command line arguments can be manipulated in program; all arguments are obtained as character string which can be converted into integer, float, long as shown in program. Even any character string if passed as an path of any file that can be used by program to file handling operation oh that file. We can see in above program, (/home/sitaram/test_progs/cmdline/cmdline_strfunc.c ) file path is passed as an command line argument which is used inside program to open the file and close the file.
Getopt() API
If we explore more on command line arguments, we have very powerful API – getopt(). It facilitates programmer to parse command line options. Programmer can give list of mandatory or optional command line options to getopt(). It can determine whether command line option is either valid or invalid as per program expected command line options. There are few getopt() specific internal variables like “optarg, optopt, opterr”
- Optarg: contains pointer to command line valid option’s argument
- Optopt: contains command line option if mandatory command line option is missing
- Opterr: set to non-zero when invalid option is provided or value of mandatory command line option is not given
Given below is basic program to understand parsing of command line options.
#include <stdio.h> #include <unistd.h> int main (int argc, char *argv[]) { int opt = 0; char *in_fname = NULL; char *out_fname = NULL; while ((opt = getopt(argc, argv, "i:o:")) != -1) { switch(opt) { case 'i': in_fname = optarg; printf("\nInput option value=%s", in_fname); break; case 'o': out_fname = optarg; printf("\nOutput option value=%s", out_fname); break; case '?': /* Case when user enters the command as * $ ./cmd_exe -i */ if (optopt == 'i') { printf("\nMissing mandatory input option"); /* Case when user enters the command as * # ./cmd_exe -o */ } else if (optopt == 'o') { printf("\nMissing mandatory output option"); } else { printf("\nInvalid option received"); } break; } } printf("\n"); return 0; }
Output of above program is given below with few combinations of command line options:
Case1: $ ./cmdline_getopt -i /tmp/input -o /tmp/output Input option value=/tmp/input Output option value=/tmp/output Case2: $ ./cmdline_getopt -i -o /tmp/output Input option value=-o Case3: $ ./cmdline_getopt -i ./cmdline_getopt: option requires an argument -- 'i' Missing mandatory input option Case4: $ ./cmdline_getopt -i /tmp/input -o ./cmdline_getopt: option requires an argument -- 'o' Input option value=/tmp/input Missing mandatory output option Case5: $ ./cmdline_getopt -k /tmp/input ./cmdline_getopt: invalid option -- 'k' Invalid option received
In above program, ‘i’ and ‘o’ are taken as mandatory input and output command line options for program using getopt() API.
We would now have basic explanation of each case executed in above program:
- In Case1, both mandatory command line options with their arguments are provided which are properly handled in first two cases of switch condition of program.
- In Case2, value of mandatory input option is not given but we can see getopt() is not intelligent enough and considered “-o” as value of ‘I’ command line option. It is not error case for getopt(), but programmer can itself add intelligence to handle such case.
- In Case3, only command line option is specified without its value and this is mandatory option so in this case getopt() would return ‘?’ and “optopt” variable is set to ‘i’ to confirm mandatory input option’s value is missing.
- In Case4, mandatory output option’s value is missing.
- In Case5, invalid command line option is given which is not mandatory or optional command line option. In this case, getopt() returned ‘?’ and optopt is not set since it is unknown character not expected by getopt().
Comments on this entry are closed.
Hi,
Thanks a lot for very nice and useful article
Haven’t use those things lately,,,,
It is bit old for me, but it is good to know…..
Well, I try to think like list of pointers, sometimes I think of those things like switch board that have wires that can be moved to another board.
Something like that….
Thank you very much. I usually feel difficult to understand the getopt () function call. Now, its clear for me.
Being from the old school of C programming I always just ground out the options from analyzing argv. Never thought to use getopt and never learned how to use it. This is great information to have. Wish I had learned it long ago.
Line 5 of cmdline_basic has the %s specifier expecting a char * and recieving an int. Its going to write to memory that doesn’t belong to it. Good article though.
Thanks for your helpful article….
Thank you very much for your post.
It is really well made.
this is just what I was looking for! Thank you very much!
Thanks for the tutorial.
Heads up, your first example crashes because of a %s in the printf trying to print argc.
Great article, it helped me a lot.
Thanks