Linux系统参数,linux基本环境

  Linux系统参数,linux基本环境

  当我们为Linux编写程序时,我们必须考虑到程序将在多任务环境中运行。这意味着多个程序将同时运行并共享机器资源,如内存、磁盘空间和CPU周期。也许一个程序会有多个实例同时运行。这时候最重要的是,这些程序之间没有交互,彼此知道对方的周围。同时,它们应该正确运行以避免冲突,例如试图同时用另一个程序写同一个文件。

  在这一章中,我们将讨论程序执行的环境,它们如何使用环境来获取关于操作环境的信息,以及这些程序的用户如何改变它们的行为。具体来说,我们将讨论以下内容:

  向程序传递参数

  环境变量

  查看时间信息

  暂存文件

  获取有关用户和主机的信息。

  并记录配置日志消息。

  发现系统的局限性

  程序参数

  用C语言编写的Linux或Unix程序运行时,由main函数执行。对于这些程序,主函数被声明为

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

  这里,argc是程序参数的个数,argv是表示参数本身的字符串数组。

  有时候我们也可以看到Linux的C程序简单的声明为

  主()

  这仍然是可行的,因为返回类型默认为int,函数不需要的通用参数也不需要声明。c和argc还是存在的,但是如果不做声明,就不能用。

  当操作系统启动一个新程序时,argc和argv被设置并传递给main。这些参数通常由另一个程序提供,通常是请求操作系统执行新程序的外壳。shell将读取给定的命令行参数,将它们分成单独的单词,并使用它们来设置argv数组。记住,在设置argc和argv之前,Linux shell通常对文件名参数进行通配符扩展,而MS-DOS shell期望程序接受带通配符的参数,并执行自己的通配符扩展。

  例如,如果我们为shell提供以下命令:

  $ myprog左右居中

  myprog程序使用以下参数启动主函数:

  argc: 4

  argv: {"myprog "," left "," right "," and center"}

  请注意,参数的数量包括程序本身的名称,argv数组包含程序名称作为其第一个元素argv[0]。因为我们在shell命令中使用引号,所以第四个参数包含一个带空格的字符串。

  如果我们使用ISO/ANSI C编写过程序,我们会对这些内容很熟悉。主参数对应于shell脚本中的position参数,$0,$1等等。但是ISO/ANSI C规定main必须返回int,X/Open的描述包含了上面给出的显示声明。

  命令行参数对于向程序传递信息非常有用。例如,我们可以在数据库程序中使用命令行参数来传递我们想要使用的数据库名称,这允许我们在多个数据库上使用同一个程序。许多实用程序也使用命令行参数来更改它们的行为或设置选项。我们可以通过使用带破折号的命令行参数来设置这些所谓的标志或开关。例如,排序程序有一个开关来反转通常的排序顺序。

  $ sort -r文件

  命令行参数很常见,正确使用真的对使用我们程序的人有很大帮助。过去,所有实用程序都实现了自己的命令选项方法,这导致了混乱。例如,看看以下命令如何读取参数:

  $ tar cvfB /tmp/file.tar 1024

  $ DD if=/dev/fd0 of=/tmp/file . DD bs=18k

  $ ls -lstr

  $ ls -l -s -t -r

  的所有命令行参数都应以破折号开头,由字母或数字组成。没有更多参数的选项可以在破折号后组织在一起。所以上面显示的两个ls命令都遵守这个约定。如果一个选项需要一个参数,那么它后面可以跟一个值。dd命令的示例不遵循此规则。他使用多个字符选项,不以破折号开头(if=/dev/fdo);tar命令将其选项与其值完全分开。

  其他程序的缺点是它们使用选项X来执行与-X相反的功能。

  正如我们所看到的,如果没有特殊的格式处理,很难记住所有这些程序选项的顺序和含义。通常,唯一的资源是使用-h(help)选项或手册页。正如我们将在后面看到的,getopt为这些问题提供了一个聪明的解决方案。现在,让我们看看传递的程序参数的处理。

  测试程序参数

  下面是一个程序args.c,用来检测自己的参数:

  #包含stdio.h

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

  {

  int arg

  for(arg=0;arg argcarg ) {

  if(argv[arg][0]==-)

  printf("选项:%s/n ",argv[arg]1);

  其他

  printf("参数%d: %s/n ",arg,argv[arg]);

  }

  退出(0);

  }

  当我们运行这个程序时,它只是打印出它的参数和检测选项。它的目的是读取一个字符串参数和一个由程序中的-f选项引入的可选文件名参数。还定义了其他选项。

  $ ./args -i -lr 你好-f fred.c

  参数0: args

  选项:一

  选项:lr

  论据3:你好

  选项:f

  论据5:弗雷德c

  操作原理

  该程序只是使用程序计数argc来设置一个循环,以检测所有的程序参数。他通过寻找一个初始破折号来检查选项。

  在这个例子中,如果我们的设计中只有-l和-r可用,那么也许我们会失去-lr本应被视为与-L-R相同的事实。

  X/Open description定义了一个命令行选项的标准用法,同时定义了一个在C程序中提供命令行开关的标准程序接口:getopt函数。

  获得命令中的选择项

  为了帮助我们遵守这些规则,Linux为我们提供了getopt函数,该函数支持带值和不带值的选项,并且易于使用。

  #包括unistd.h

  int getopt(int argc,char *const argv[],const char * optstring);

  extern char * optarg

  extern int optind,opterr,optopt

  Getopt函数读取传递给程序主函数的argc和argv参数以及一个选项描述符字符串,该字符串通知getopt为该程序定义了哪些选项,以及这些选项是否有关联的值。Optstring只是一个简单的字符列表,每个字符代表一个字符选项。如果一个字符后跟一个冒号,则表明该选项有一个与之关联的值,应该作为下一个参数读取。bash中的getopts命令也有类似的功能。

  例如,以下调用可用于处理我们之前的示例:

  getopt(argc,argv," if:lr ");

  他允许使用简单的选项-i、-l、-r和-f选项,后跟filename参数。使用相同的参数但以不同的顺序调用该命令将会改变其行为。当我们遇到下面的示例代码时,可以尝试一下。

  getopt的返回结果是argv数组中的下一个选项字符(如果有)。我们反复调用getopt来依次获取每个选项。他有以下行为:

  如果选项有一个参数值,那么这个值由外部变量optarg指向。

  当没有要处理的选项时,Getopt返回-1。一个特殊的参数--将使getopt停止搜索。

  如果有未被认可的选项,他会返回?选项将存储在外部变量optopt中。

  如果一个选项需要一个参数值(例如,我们示例中的-f),但是没有参数值,getopt将返回。

  外部变量optind被设置为要处理的下一个参数的索引。Getopt将使用这个变量来记录他在哪里处理它。程序通常不需要这个变量。当处理完所有选项参数后,optind将在argv数组的末尾指出在哪里可以找到剩余的参数。

  某些版本的getopt在遇到第一个非选项参数return -1和set optind时会停止。的其他版本,如Linux提供的版本,可以处理程序参数中的所有选项。请注意,在本例中,getopt将重置argv数据,以便可以将所有非选项参数组织在一起,从argv[optind]开始。对于getopt的GNU版本,它的行为由环境变量POSIXLY_CORRECT控制。如果设置,getopt将在第一个非选项参数处停止。此外,一些getopt实现会打印未知选项的错误消息。注意,POSIX的描述表明,如果opterr变量为非零值,getopt将向stderr输出一条错误消息。

  实验-getopt

  现在我们在示例中使用getopt,并将这个新程序称为argopt.c:

  #包含stdio.h

  #包括unistd.h

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

  {

  int opt

  while((opt=getopt(argc,argv," if:lr "))!=-1) {

  开关(可选){

  案例“I”:

  案例“l”:

  案例“r”:

  printf("选项:%c/n ",opt);

  打破;

  案例“f”:

  printf("文件名:%s/n ",optarg);

  打破;

  案例“:”:

  printf("选项需要一个值/n ");

  打破;

  案子吗?

  printf("未知选项:%c/n ",optopt);

  打破;

  }

  }

  for(;optind argcoptind)

  printf("参数:%s/n ",argv[optind]);

  退出(0);

  }

  现在,当我们运行这个程序时,我们发现所有的命令行参数都被自动处理:

  $ ./argopt -i -lr 你好-f fred.c -q

  选项:一

  选项:l

  选项:r

  文件名:弗雷德. c

  隐语:无效选项-—q

  未知选项:q

  辩君:你好

  操作原理

  程序将重复调用getopt来处理选项参数,直到没有要处理的选项,此时getopt将返回-1。将对每个选项执行此操作,包括处理未知选项以查看是否有选项参数值。根据我们的getopt版本,我们得到的输出与上面不同,尤其是错误消息,但是意思很清楚。

  一旦处理完所有选项,程序将简单地打印出剩余的参数,这与前面的示例相同,但由optind启动。

  getopt_long

  许多Linux程序也接受比我们在上面的例子中使用的单字符选项更有意义的参数。GNU C库包含一个名为getopt_long的getopt版本,它可以接受由双破折号引入的所谓长参数。

  我们使用getopt_long来创建我们上面的示例程序的新版本,这样他就可以用一个与我们的选项等价的长参数来调用它。

  事实上,新的长选项可以与原来的单字符选项混合使用。长选项只要不一样也可以缩写。带参数的长选项可以以格式- option=value给出,如下所示:

  $ ./long opt-initl-file=Fred . c 你好

  选项:一

  选项:l

  文件名:弗雷德. c

  辩君:你好

  新程序longopt.c如下:

  #包含stdio.h

  #包括unistd.h

  #定义_ GNU _源

  #include getopt.h

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

  {

  int opt

  结构选项longopts[]={

  {"initialize ",0,NULL, i},

  {"file ",1,NULL, f},

  {"list ",0,NULL, l},

  {"restart ",0,NULL, r},

  {0,0,0,0}};

  while((opt=getopt_long(argc,argv," if:lr ",longopts,NULL))!=-1) {

  开关(可选){

  案例“I”:

  案例“l”:

  案例“r”:

  printf("选项:%c/n ",opt);

  打破;

  案例“f”:

  printf("文件名:%s/n ",optarg);

  打破;

  案例“:”:

  printf("选项需要一个值/n ");

  打破;

  案子吗?

  printf("未知选项:%c/n ",optopt);

  打破;

  }

  }

  for(;optind argcoptind)

  printf("参数:%s/n ",argv[optind]);

  退出(0);

  }

  操作原理

  与getopt相比,getopt_long多了两个参数。第一个是结构数组,它描述了long选项并告诉getopt_long如何处理它。第二个额外参数是指向optind变量的指针,该变量可用作长选项版本;对于每个被识别的长选项,它在长选项数组中的索引可以被写入这个变量。在我们的例子中,我们不需要这些信息,所以我们使用NULL作为第二个额外的参数。

  长选项数组由一些struct option类型的结构组成,每个结构描述长选项的行为。该数组必须以包含零的结构结尾。

  长选项结构在getopt.h中定义,必须包含在_GNU_SOURCE中才能允许getopt_long函数:

  结构选项{

  const char * name

  int有_ arg

  int * flag

  int val

  };

  该结构的成员如下:

  命名长选项的名称。只要它们的缩写不与其他选项冲突,就可以被接受。

  Has_arg此选项是否有参数。如果不需要该参数,将其设置为0;如果一定要有参数值,就设置为1;如果有可选参数,将其设置为2。

  将flag设置为NULL,以便getopt_long在找到该选项时返回val中指定的值。否则,getopt_long将返回0,并将val的值写入flag所指向的变量。

  Getopt _ long是该选项返回的值。

  要了解与getopt的GNU扩展相关的其他选项和相关函数,可以查看getopt的手册页。

Linux系统参数,linux基本环境