《Linux程序设计》第四章(程序参数、环境变量、时间和日期)

1.程序参数:C语言编写的linux或者unix程序的入口是main函数。该函数声明如下:
int main(int argc,char* argv[]);其中argc代表参数个数,argv是一个字符串数组。参数个数包括程序名自身,argv数组的
第一个元素是argv[0]。命令行参数在向程序传递信息方面很有用。可以使用短横线(-)开头的命令行参数来设置标志或者开关。
有的时候还会使用+来表示和-相反的功能。

#include <stdio.h>
#include <stdlib.h>
int main(int argc,char* argv[])
{
 int arg;
 for(arg=0;arg<argc;arg++){
 if(argv[arg][0]=='-'){printf("option: %s\n",argv[arg]+1);}
 else{
 printf("argument %d: %s\n",arg,argv[arg]);
}
}
exit(0);
}

运行测试用例和结果如下:

jiang@ubuntu:~$ ./args -i -lr 'hi there' -f fred.c
argument 0: ./args
option: i
option: lr
argument 3: hi there
option: f
argument 5: fred.c

但有一个问题:-lr选项应该和-l或者-r选项一样处理。因此linux提供了getopt函数。

  • 1.getopt
    该函数支持需要关联和不需要关联的选项。函数原型如下:
    #include <unistd.h>
    int getopt(int argc,char* const argv[],const char *optstring);//将传递给main的两个参数作为参数,同时接受一个选项指定
    符字符串optstring,该字符串告诉getopt哪些选项可以用,以及它们是否有关联值。optstring是一个字符列表。
    每个字符代表一个单字符选项。如果一个字符后弄紧跟一个冒号(:),则表明该选项有一个关联值作为下一个参数。
    extern char *optarg;
    extern int optind, opterr,optopt;
    如果一个选项要求有一个关联值,但用户未提供这个值,getopt将返回一个问号;但如果将选项字符串的第一个字符设置为冒号,
    那么getopt将在用户未提供值的情况下返回冒号而不是问号。
  • 外部变量:extern char *optarg;  //选项的参数指针
    extern int optind,   //下一次调用getopt的时,从optind存储的位置处重新开始检查选项。 
    extern int opterr,  //当opterr=0时,getopt不向stderr输出错误信息。
    extern int optopt;  //当命令行选项字符不包括在optstring中或者选项缺少必要的参数时,该选项存储在optopt 中,getopt返回'?’
  • 以下是函数举例。
      1 #include <stdio.h>
      2 #include <unistd.h>
      3 #include <stdlib.h>
      4 int main(int argc,char *argv[])
      5 {
      6  int opt;
      7  while((opt=getopt(argc,argv,":if:lr"))!=-1)
      8 {
      9  switch(opt){
     10  case 'i':
     11  case 'l':
     12  case 'r':
     13    printf("option: %c\n",opt);
     14    break;
     15  case 'f':
     16    printf("filename:%s\n",optarg);
     17    break;
     18  case ':':
     19    printf("option needs a value\n");
     20    break;
     21  case '?':
     22    printf("unknown option:%c\n",optopt);
     23    break;
     24 }
     25 }
     26 for(;optind<argc;optind++)
     27 {
     28  printf("argument:%s\n",argv[optind]);
     29 }
     30 exit(0);
     31 }
    

    运行结果如下:

    jiang@ubuntu:~$ gcc -o getopt getopt.c
    jiang@ubuntu:~$ ./getopt -i -lr 'hi there' -f fred.c -q
    option: i
    option: l
    option: r
    filename:fred.c
    unknown option:q
    argument:hi there
    

    可是有的时候我们需要的是长指令,getopt_long函数用来处理长指令

getopt_long
getopt_long我getopt的另一个版本。接受以双划线(--)开始的长参数。示例函数如下:

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #define _GNU_SOURCE
  5 #include <getopt.h>
  6 int main(int argc,char *argv[])
  7 {
  8     int opt;
  9     struct option longopts[]={
 10     {"initialize",0,NULL,'i'},
 11     {"file",1,NULL,'f'},
 12     {"list",0,NULL,'l'},
 13     {"restart",0,NULL,'r'},
 14     {0,0,0,0}
 15     };
 16     while((opt=getopt_long(argc,argv,":if:lr",longopts,NULL))!=-1){
 17         switch(opt){
 18         case 'i':
 19         case 'l':
 20         case 'r':
 21             printf("option:%c\n",opt);
 22             break;
 23         case 'f':
 24             printf("filename:%s\n",optarg);
 25             break;
 26         case ':':
 27             printf("option needs a value\n");
 28             break;
 29         case '?':
 30             printf("unknown option: %c\n",optopt);
 31             break;
 32         }
 33     }
 34     for(;optind<argc;optind++){
 35         printf("argument: %s\n",argv[optind]);
 36     }
 37     exit(0);
 38 }

getopt_long比getopt多两个参数。第一个参数是一个数组,用来描述每个长选项;第二个参数是一个变量指针,相当于optind的长指令版本。测试程序结果如下:

jiang@ubuntu:~$ ./longopt --init -l --file=fred.c 'hi there'
option:i
option:l
filename:fred.c
argument: hi there

2.环境变量

c语言可以使用getenv和putenv函数来访问和改变环境变量。函数原型如下
char *getenv(const char *name);
int putenv(const char* string);
环境由一组格式为“名字=值”的字符串组成。getenv以给定的名字搜索环境中的一个字符串,并返回与改名字相关的值。
putenv以一个格式为“名字=值”的字符串作为参数,并将该字符串加到当前环境中。

getenv和putenv的实验和结果:

1 #include <stdlib.h>
  2 #include <stdio.h>
  3 #include <string.h>
  4 int main(int argc,char* argv[])
  5 {
  6  char *var,*value;
  7  if(argc==1||argc>3){
  8      fprintf(stderr,"usage:environ var [value]\n");
  9      exit(1);
 10  }
 11  var= argv[1];
 12  value=getenv(var);
 13  if(value){
 14  printf("Valueable %s has value %s \n",var,value);
 15  }else{
 16  printf("Valueable %s has no value\n",var);
 17  }
 18  if(argc==3){
 19  char *string;
 20  value=argv[2];
 21  string=malloc(strlen(var)+strlen(value)+2);
 22  if(!string){
 23  fprintf(stderr,"out of memory\n");
 24  exit(1);
 25  }
 26 
 27  strcpy(string,var);
 28  strcat(string,"=");
 29  strcat(string,value);
 30  printf("Calling putenv with: %s\n",string);
 31  if(putenv(string)!=0){
 32  fprintf(stderr,"putenv failed\n");
 33  free(string);
 34  exit(1);
 35  }
 36  }
 37  value=getenv(var);
 38  if(value)
 39  {
 40   printf("New value of %s is %s\n",var,value);
 41  }else{
 42   printf("New value of %s is null?\n",var);
 43  }
 44  exit(0);
 45 }

结果如下:

jiang@ubuntu:~$ gcc -o environ environ.c
jiang@ubuntu:~$ ./environ HOME
Valueable HOME has value /home/jiang 
New value of HOME is /home/jiang
jiang@ubuntu:~$ ./environ FRED
Valueable FRED has no value
New value of FRED is null?
jiang@ubuntu:~$ ./environ FRED hello
Valueable FRED has no value
Calling putenv with: FRED=hello
New value of FRED is hello
jiang@ubuntu:~$ ./environ FRED
Valueable FRED has no value
New value of FRED is null?

环境变量有的时候就像是全局变量,使用的时候应当小心,可能会使得程序难以调试。

使用environ变量打印环境变量示例程序:

  1 #include <stdlib.h>
  2 #include <stdio.h>
  3 extern char **environ;
  4 int main()
  5 {
  6     char **env=environ;
  7     while(*env){
  8         printf("%s\n",*env);
  9         env++;
 10     }
 11     exit(0);
 12 }

整个程序遍历了environ变量。environ是linux的一个全局变量。

3.时间和日期
可以通过调用time函数得到底层时间值。函数原型如下:
#include <time.h> time_t time(time_t *tloc);

UNIX和Linux的时间原点是1970年1月1日午夜0点。从改时间原点开始按照秒计时。

  1 #include <time.h>
  2 #include <stdio.h>
  3 #include <unistd.h>
  4 #include <stdlib.h>
  5 int main()
  6 {
  7     int i;
  8     time_t the_time;
  9     for(i=1;i<=10;i++){
 10         the_time=time((time_t *)0);
 11         printf("The time is %ld\n",the_time);
 12         sleep(2);
 13     }
 14     exit(0);
 15 }

结果如下:

jiang@ubuntu:~$ ./envtime
The time is 1538661243
The time is 1538661245
The time is 1538661247
The time is 1538661249
The time is 1538661251
The time is 1538661253
The time is 1538661255
The time is 1538661257
The time is 1538661259
The time is 1538661261

另外的时间函数:

#include <time.h>
double difftime(time_t time1,time_t time2);//该函数用来计算两个时间之间的差。
struct tm *gmtime(const time_t timeval);//将时间分解为一个结构

  1 #include <time.h>
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 
  5 int main()
  6 {
  7     struct tm *tm_ptr;
  8     time_t the_time;
  9 
 10     (void) time(&the_time);
 11     tm_ptr=gmtime(&the_time);
 12 
 13     printf("Raw time is %ld\n",the_time);
 14     printf("gmtime gives:\n");
 15     printf("date: %02d/%02d/%02d\n",tm_ptr->tm_year,tm_ptr->tm_mon+1,tm_ptr->tm_mday);
 16     printf("time:%02d:%02d:%02d\n",tm_ptr->tm_hour,tm_ptr->tm_min,tm_ptr->tm_sec);
 17     exit(0);
 18 }

运行结果如下:

jiang@ubuntu:~$ ./gmtime
Raw time is 1538662414
gmtime gives:
date: 118/10/04
time:14:13:34
jiang@ubuntu:~$ ./gmtime;date
Raw time is 1538662422
gmtime gives:
date: 118/10/04
time:14:13:42
Thu Oct  4 07:13:42 PDT 2018

struct tm *localtime(const time_t *timeval);//不同时区同一时刻创建的文件都会有相同的创建时间。使用localtime函数查看当地时间。
time_t mktime(struct tm *timeptr);//将已分解出来的tm结构转化成为原始time_t时间值。

char *asctime(const struct tm *timeptr);//这两个函数都表示像date那样友好地输出时间
char *ctime(const time_t *timeval);

size_t strftime(char* s,size_t maxsize, const char *format, struct tm *timeptr);//strftime函数能够对格式有更多的控制和输出。

猜你喜欢

转载自blog.csdn.net/eriHanami/article/details/82937661