【Linux】程序编写之快速创建命令行参数

前言

Linux中,程序在命令行中经常需要添加参数运行,自己编写进行参数解析比较麻烦,可以使用GNU C提供的函数getoptgetopt_longgetopt_long_only来快速解析命令行参数

关于命令行参数

命令行参数可以分为两类:

  • 短选项,-
  • 长选项,--

两者后面都可选择性添加额外参数。比如--block-size=SIZE,SIZE便是额外的参数。

getopt_long函数

getopt函数只能处理短选项,而getopt_long函数两者都可以,函数声明如下:

#include <unistd.h>  
extern char *optarg;  
extern int optind, opterr, optopt;  
#include <getopt.h>
int getopt(int argc, char * const argv[],const char *optstring);  
int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);  
int getopt_long_only(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);

参数介绍

以上三个函数都适用

  1. argc和argv和main函数的两个参数一致。
  2. optstring: 表示短选项字符串,形式如a:b:c:d:,分别表示程序支持的命令行短选项有-a、-b、-c、-d,冒号含义如下: 一个字符,后接一个冒号——表示选项后面带一个参数,如-a 100
  3. longopts:表示长选项结构体。结构如下:
    struct option
    {  
         const char *name;  //选项名称
         int         has_arg;  //后面是否跟参数, --num 100
         int        *flag;  //一般为NULL
         int         val;  //当flag为NULL时,指定getopt_long函数返回val
    };
    
    4.longindex:一般为NULL,非空时记录当前找到参数在longopts中的下标值。

返回值介绍

  1. 如果短选项找到,那么将返回短选项对应的字符。
  2. 如果长选项找到,如果flag为NULL,返回val。如果flag不为空,返回0
  3. 如果遇到一个选项没有在短字符、长字符里面。或者在长字符里面存在二义性的,返回“?”
  4. 如果解析完所有字符没有找到(一般是输入命令参数格式错误,eg: 连斜杠都没有加的选项),返回“-1”
  5. 如果选项需要参数,忘了添加参数。返回值取决于optstring,如果其第一个字符是“:”,则返回“:”,否则返回“?”。

注意:

  1. longopts的最后一个元素必须是全0填充,否则会报段错误
  2. 短选项中每个选项都是唯一的。而长选项如果简写,也需要保持唯一性。

全局变量optarg

  • optarg常用:表示当前选项对应的参数值。
  • optind:表示的是下一个将被处理到的参数在argv中的下标值。
  • opterr:如果opterr = 0,在getopt、getopt_long、getopt_long_only遇到错误将不会输出错误信息到标准输出流。opterr在非0时,向屏幕输出错误。
  • optopt:表示没有被未标识的选项。

示例程序

为了学习进程间通信之消息队列,下面以创建消息队列、发送数据到消息队列、读取消息队列数据三个进程为例进行示例:

创建消息队列

编译:gcc -o make_msgqueue make_msgqueue.c
执行:

./creat_msg_queue 
Message Queue key: 67201.
Message queue id: 0.
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>

int main() {
  int messagequeueid;
  key_t key;
  //ftok 会根据这个文件的 inode,生成一个近乎唯一的 key
  if((key = ftok("./messagequeuekey", 1024)) < 0) {
      perror("ftok error");
      exit(1);
  }

  printf("Message Queue key: %d.\n", key);
  //创建消息队列
  if ((messagequeueid = msgget(key, IPC_CREAT|0777)) == -1) {
      perror("msgget error");
      exit(1);
  }

  printf("Message queue id: %d.\n", messagequeueid);
}

发送消息

编译:gcc -o send send_msg.c
运行:./send -i 0 -t 123 -m "hello world"
可以看到后面跟了很多参数,需要快速解析出来

/*
下面的这段程序,getopt_long、do-while 循环以及 switch,是用来解析命令行参数的。
optarg变量为全局变量,用来承载解析后的参数
命令行参数的格式定义在 long_options 里面。
每一项的第一个成员“id”“type”“message”是参数选项的全称,第二个成员都为 1,表示参数选项后面要跟参数,最后一个成员’i’‘t’'m’是参数选项的简称。
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <getopt.h>
#include <string.h>

//消息类型
struct msg_buffer {
    long mtype;
    char mtext[1024];
};

int main(int argc, char *argv[]) {
  int next_option;
  //短选项
  const char* const short_options = "i:t:m:";
  //长选项
  const struct option long_options[] = {
    { "id", 1, NULL, 'i'},
    { "type", 1, NULL, 't'},
    { "message", 1, NULL, 'm'},
    { NULL, 0, NULL, 0 }//最后一项必须全0,否则段错误
  };
  
  int messagequeueid = -1;//消息队列id
  struct msg_buffer buffer;
  buffer.mtype = -1;
  int len = -1;
  char * message = NULL;
  do {
    next_option = getopt_long (argc, argv, short_options, long_options, NULL);
    switch (next_option)
    {
      case 'i':
        messagequeueid = atoi(optarg);
        break;
      case 't':
        buffer.mtype = atol(optarg);
        break;
      case 'm':
        message = optarg;
        len = strlen(message) + 1;
        if (len > 1024) {
          perror("message too long.");
          exit(1);
        }
        memcpy(buffer.mtext, message, len);
        break;
      default:
        break;
    }
  }while(next_option != -1);


  if(messagequeueid != -1 && buffer.mtype != -1 && len != -1 && message != NULL){
    if(msgsnd(messagequeueid, &buffer, len, IPC_NOWAIT) == -1){//发送数据到消息队列
      perror("fail to send message.");
      exit(1);
    }
  } else {
    perror("arguments error");
  }  
  return 0;
}

接收消息

编译:gcc -o recv recv_msg.c
运行:

./recv -i 0 -t 123
received message type : 123, text: hello world.

#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <getopt.h>
#include <string.h>


struct msg_buffer {
    long mtype;
    char mtext[1024];
};


int main(int argc, char *argv[]) {
  int next_option;
  const char* const short_options = "i:t:";
  const struct option long_options[] = {
    { "id", 1, NULL, 'i'},
    { "type", 1, NULL, 't'},
    { NULL, 0, NULL, 0 }
  };
  
  int messagequeueid = -1;
  struct msg_buffer buffer;
  long type = -1;
  do {
    next_option = getopt_long (argc, argv, short_options, long_options, NULL);
    switch (next_option)
    {
      case 'i':
        messagequeueid = atoi(optarg);
        break;
      case 't':
        type = atol(optarg);
        break;
      default:
        break;
    }
  }while(next_option != -1);


  if(messagequeueid != -1 && type != -1){
    if(msgrcv(messagequeueid, &buffer, 1024, type, IPC_NOWAIT) == -1){
      perror("fail to recv message.");
      exit(1);
    }
    printf("received message type : %d, text: %s.", buffer.mtype, buffer.mtext);
  } else {
    perror("arguments error");
  }
  
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值