≡菜单

解析命令行参数的C argc和argv示例

无论何时在终端上执行程序,都可以传递程序期望的一些参数,这些参数可以在程序执行期间使用。在这里,系统提供了内部工具来维护在执行程序时从用户传递的所有参数。这些参数称为“命令行参数”。

在本教程中,我们将对命令行参数的理解与工作程序相映射,以清晰明了的方式更好地理解命令行参数。但是在跳转到程序之前,我们应该知道系统如何提供命令行参数的工具。众所周知,每个C程序都必须具有main()函数,而命令行参数的功能则由main()函数本身提供。当在下面给出声明时,在程序中使用了声明,然后程序具有使用/操纵命令行参数的便利。

int main (int argc, char *argv[])

在这里,argc参数是在执行时传递给可执行文件的命令行参数总数(包括可执行文件的名称作为第一个参数)。 argv参数是在执行时传递给可执行文件的每个命令行参数的字符串数组。如果您不熟悉C编程,则应首先了解如何 C数组 作品。

下面给出的是使用命令行参数的工作程序。

 #include <stdio.h>

 int main (int argc, char *argv[]) {
 int i=0;
 printf("\ncmdline args count=%s", argc);

 /* First argument is executable name 上 ly */
 printf("\nexe name=%s", argv[0]);

 for (i=1; i< argc; i++) {
     printf("\narg%d=%s", i, argv[i]);
 }

 printf("\n");
 return 0;
 }

下面给出的是程序执行时的输出。

$ ./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

在上面的输出中,我们可以看到参数总数由main()的“ argc”参数在内部维护,该参数包含值“ 7”(其中一个参数是可执行文件名称,而“ 6”是传递给程序的参数)。参数值存储在main()的“ argv”参数中,该参数是字符串数组。在这里,main()函数将每个参数值存储为字符串。我们可以看到,遍历“ argv”数组,我们可以获取程序中所有传递的参数。

main()函数还有一个声明,它提供了在程序内部处理环境变量的附加功能。像在argv []数组中维护的参数一样,main()函数具有内部功能,可以将所有系统环境变量维护为字符串数组,可以将其用作main()函数参数。以下是声明。

int main (int argc, char *argv[], char **envp)

下面给出的是使用命令行参数和环境变量的工作程序。

#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 上 ly */
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;
}

上面程序的输出如下。

$ ./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=//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
$

在上面的输出中,我们可以看到可以从main()函数的第三个参数获得所有系统环境变量,这些参数在程序中遍历并在输出中显示。

将命令行参数传递给编程和操纵参数

下面给出的是处理命令行参数的程序。

#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 上 ly */
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 上  failure */
if ( file == NULL) {
    printf("\nCould not open file");
  }
else {
    printf("\nFile (%s) opened", argv[3]);
    /* Closing file */
    fclose(file);
  }

printf("\n");
return 0;
}

上面程序的输出如下。

 $ ./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

在上面的输出中,我们可以看到可以在程序中操作命令行参数。所有参数都以字符串形式获取,可以将其转换为整数,浮点数,如程序所示。即使是任何字符串,如果作为任何文件的路径传递,程序也可以使用它来对该文件进行文件处理操作。我们可以在上面的程序中看到(/home/sitaram/test_progs/cmdline/cmdline_strfunc.c)文件路径作为命令行参数传递,该路径在程序内部用于打开文件和关闭文件。

Getopt()API

如果我们在命令行参数上进行更多研究,我们将拥有非常强大的API – getopt()。它有助于程序员解析命令行选项。程序员可以将强制或可选命令行选项列表提供给getopt()。它可以根据程序预期的命令行选项确定命令行选项是有效还是无效。几乎没有特定于getopt()的内部变量,例如“ optarg,optopt,opterr”

  • Optarg:包含指向命令行有效选项参数的指针
  • Optopt:如果缺少必需的命令行选项,则包含命令行选项
  • Opterr:在提供无效选项或未提供强制命令行选项的值时设置为非零

下面给出的是基本程序,用于了解命令行选项的解析。

 

#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;
 }

下面是上述程序的输出,其中包含一些命令行选项组合:

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

在上述程序中,“ i”和“ o”被用作使用getopt()API的程序的强制输入和输出命令行选项。

现在,我们将对上述程序中执行的每种情况有基本的解释:

  • 在Case1中,提供了两个强制性命令行选项及其参数,在程序的切换条件的前两种情况下可以正确处理。
  • 在Case2中,未提供强制输入选项的值,但我们可以看到getopt()不够智能,因此将“ -o”视为“ I”命令行选项的值。对于getopt()来说,这不是错误的情况,但是程序员本身可以添加智能来处理这种情况。
  • 在Case3中,仅指定了命令行选项而没有其值,这是必选选项,因此在这种情况下,getopt()将返回“?”,并且将“ optopt”变量设置为“ i”以确认缺少必选输入选项的值。
  • 在Case4中,缺少强制输出选项的值。
  • 在Case5中,给出了无效的命令行选项,该选项不是必需的或可选的命令行选项。在这种情况下,getopt()返回了“?”,并且未设置optopt,因为它是getopt()不需要的未知字符。

如果您喜欢这篇文章,您可能还会喜欢..

  1. 50个Linux Sysadmin教程
  2. 50个最常用的Linux命令(包括示例)
  3. 排名前25位的最佳Linux性能监视和调试工具
  4. 妈妈,我找到了! – 15个实用的Linux Find命令示例
  5. Linux 101 Hacks第二版电子书 Linux 101黑客手册

Bash 101 Hacks书 Sed和Awk 101黑客手册 Nagios Core 3书 Vim 101黑客手册

{ 10 评论… 加一 }

  • 贾拉尔·哈吉霍拉玛利 2013年1月31日,上午4:59

    你好

    非常感谢您写的非常好和有用的文章

  • 杜斯科科西卡 2013年2月8日,上午4:36

    避风港’最近不要使用这些东西,

    对我来说有点老了,但很高兴知道…..

    好吧,我试图像指针列表那样思考,有时我想到的是诸如开关板之类的东西,这些电线可以移动到另一块板上。

    像这样….

  • 西瓦·克里希纳(Siva Krishna) 2013年2月24日,上午4:15

    非常感谢你。我通常很难理解getopt()函数调用。现在,对我来说很清楚。

  • 卡尔·S-P 2013年3月18日,下午12:36

    我来自C语言编程的老派,我始终只是从分析argv入手。从未想过使用getopt,也从未学习过如何使用它。这是很棒的信息。希望我早就学会了。

  • 法庭 2014年4月23日,下午7:17

    cmdline_basic的第5行的%s说明符期望一个char *并接收一个int。它要写入的内存不会’属于它。好文章。

  • Sepahrad Salour 2015年10月3日,上午2:41

    感谢您的有用文章….

  • 亚历克斯 2016年2月18日,上午2:08

    非常感谢您的帖子。
    做得真好。

  • lDarkllArg 2016年3月20日,上午9:54

    这就是我想要的!非常感谢你!

  • 汤姆 2016年6月22日,下午7:03

    感谢您的教程。
    抬起头来,您的第一个示例由于在printf中尝试打印argc的%s而崩溃。

  • 保罗 2017年3月12日,下午1:46

    很棒的文章,对我有很大帮助。

    谢谢

发表评论