当前位置:网站首页 > 技术博客 > 正文

getopt optarg



  前言:近期模仿磊哥的一个命令工具,遇到了shell里的getopt命令,它可以接受长短命令参数,原命令里只接了2个参数,我模仿的命令里需要接收3个参数,且都有长短写法,模拟了半天始终无法获取正确的参数,于是开始研究getopt命令。于是有了下面的转载文章

引用自:https://blog.csdn.net/wanglz666/article/details/

先从一个较为明了的语法开始

这里,getopt所带参数可以分成三个部分:

  • -o和选项是getopt命令自身的选项
  • parameters是待解析的参数(如shell传入的参数)
  • -o选项后面的optstring用来指示解析parameters的方式

来看一个简单的例子

对应到命令格式

getopt将根据optstring从左到右解析parameters。每个parameter将被解析为短选项(如上例中的-a)、长选项、选项参数(an argument to an option)及非选项参数(a non-option parameter)。

Tip: 这里的短选项仅指parameters中解析出的短选项,而非getopt自带的短选项

getopt的-o选项用来指示parameters中包含的短选项。parameters中的短选项由符号和紧连其后的一个字符构成。如上述简单例子中-o后面的a:,指示parameters中可以包含一个形如-a 的短选项。

  • a:中还有一个冒号,这指示-a有一个required argument;
  • 如果是-a::,有两个冒号,则指示-a有一个optional argument;
  • 如果仅仅是-a,没有冒号,则指示-a后面不需要任何argument,就好比很多命令中用来查看版本的-v选项,就是不用带任何argument的。

看例子

  • required argument的例子
  • optional argument的例子

可以看到,在optional argument的第二个命令中,如果para_for_a不紧跟在-a之后,则被当做了非选项参数。而-a选项需要的选项参数则被默认置空。

在-o后面也可以指定多个短选项,直接写在一起就行了。

看例子

输出结果

该例中指定了一个无参数的-a选项,一个有optional argument的-b选项,以及一个有required argument的-c选项。

如例子

这里指定了这个长选项。

  • 中还有一个冒号,这指示有一个required argument;
  • 如果是,有两个冒号,则指示有一个optional argument;
  • 如果仅仅是,没有冒号,则指示后面不需要任何argument,就好比很多命令中用来查看版本的选项,就是不用带任何argument的。

不过,上面的那个例子后面注释了一个error。如果尝试执行上面的那个例子的话,可以看到,并没有出现预期中的结果。

原因是因为getopt对-o选项的处理。参看对-o选项的说明,有这样一句

If this option is not found, the first parameter of getopt that does not start with a `-’ (and is not an option argument) is used as the short options string.

这句话的意思是说,如果getopt命令没有发现-o选项,则会尝试去找默认的short option string。

如果我们尝试执行这样的命令

其实也可以写成

我们会得到以下的输出

具体是如何将alongprf这几个字符解析成短选项的,我暂时没有去深入了。

解决方法是明确指定-o为空,如下

此时,即可得到输出

当初这个问题是参考的stackExchange上的Q&A

在接下来看更具体的例子之前,我们先来看看双引号对getopt命令的作用。

这两个命令的输出有细微的区别
第一个命令是
第二个命令是
第二个比第一个多了一个空格。

这两个命令区别明显
第一个命令的输出是
第二个命令的输出是

对于第一个命令的输出,貌似跟预期的也不大一样。这是因为-a是getopt本身自带的一个选项,这样para_a就被解析成了一个non-option parameter。

对于双引号造成的区别,应该和shell的expansion有关,还不是很理解。但可以看到的是,双引号使得空格保留下来了,作为了参数的一部分,使得getopt在处理时,将 当做了一个整体。

Tip:这里没有使用
man getopt中有说明 “The second part will start at the first non-option parameter that is not an option argument, or after the first occurrence of .”
也就是说,如果没有的话,则getopt会将从第一个不是用来指定选项的参数(non-option parameter) 开始,将其后的内容解释为getopt命令中的parameters部分。

这里对eval set和shift进行说明。

较简单,即是将位置参数进行左移。

位置参数是指shell中 ,等参数。

用来设置位置参数

我们结合set和shift来写个例子

依次执行以上命令(或写在shell脚本中执行),得到的输出如下

eval是对其后的命令再次进行shell解析,比如参数替换什么的。

在man getopt的DESCRIPTION一节的最后一段,有这么一句

Traditional implementations of getopt(1) are unable to cope with whitespace and other (shell-specific) special characters in arguments and non-option parameters. To solve this problem, this implementation can generate quoted output which must once again be interpreted by the shell (usually by using the eval command).

这意思就是在示例中eval命令是用来保留一些特殊字符,如空格的。

感觉这里eval的作用和双引号有点像,然后在代码的注释中,还有两处essential。分别是说的双引号essential,以及eval中的双引号essential。这里大约都与特殊符号有关吧。

更进一步的解释可以参考Bash: Preserving Whitespace Using set and eval,这篇文章最后一点也没看明白。。。

使用例子中提供的命令,这里面包含了很多特殊符号。

  • 两处引号均存在的输出
  • 仅去除的引号的输出
  • 仅去除eval中的引号的输出
  • 两处引号均去除的输出

从上面的结果中看到,如果的引号缺失了,会使得和的空格丢失;而引号是否缺失,似乎并无影响。

不是很明白。。。

  • 上一篇: redis是干啥的
  • 下一篇: sprintf函数的用法3%d
  • 版权声明


    相关文章:

  • redis是干啥的2025-01-16 12:01:00
  • linux cpu压力测试工具2025-01-16 12:01:00
  • java操作zip2025-01-16 12:01:00
  • linux系统中fork函数的作用2025-01-16 12:01:00
  • 成员变量和局部变量作用范围2025-01-16 12:01:00
  • sprintf函数的用法3%d2025-01-16 12:01:00
  • 单点登录原理与简单实现2025-01-16 12:01:00
  • java线程池讲解2025-01-16 12:01:00
  • 分词平台2025-01-16 12:01:00
  • pwn控制的基本原理2025-01-16 12:01:00