Linux下getopt函数的使用

2023-11-20

getopt为解析命令行参数函数,它是Linux C库函数。使用此函数需要包含系统头文件unistd.h。

getopt函数声明如下:

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

其中函数的argc和argv参数通常直接从main的参数直接传递而来。optstring是一个包含合法选项字符的字符串。如果字符后跟一个冒号”:”,则该选项要求有参数。在argv中以“-“开头的都视作选项,“-“后的字符是选项字符。getopt会返回在argv中的选项字符,此字符会对应optstring中的字符。如果getopt被重复调用,它返回下一个选项字符。如果不再有可识别的选项字符,将返回-1。

如果getopt找到另一个选项字符,则返回该字符,更新外部变量optind和静态变量nextchar,以便下次调用getopt可以重复使用接下来的选项字符。如果成功找到选项,getopt返回该选项字符。如果所有命令行选项已被解析,getopt返回-1.如果getopt遇到一个选项字符不在optstring中,那么将返回"?".

如果getopt遇到一个缺少参数的选项,则返回值取决于optstring中的第一个字符,如果是":",则返回":",否则返回"?".

默认情况下,getopt会调换argv中的内容,将非选项放在最后。这样当getopts读取完所有的选项以后,optind会指向非选项的参数。

在处理选项列表时,getopt可以检测两种错误:(1).一个选项字符在optstring中并没有指定;(2).缺少选项参数。默认情况下,getopt在标准错误上输出错误信息,将错误的选项字符放在optopt中,并返回"?"作为函数结果。如果调用者将全局变量opterr设置为0,那么getopt不会输出错误信息(默认情况下,opterr是一个非零值)。如果optstring中的第一个字符是冒号":",那时getopt同样不会打印错误信息。另外,getopt将返回":"代替返回"?"以表示缺少选项参数。

getopt()所设置的全局变量包括:

(1). char *optarg:当前选项的参数。

(2). int optind: 是在argv中要处理的下一个元素的索引。系统初始化此值为1.调用者可以将其重置为1以重新开始扫描相同的argv,或扫描一个新的参数向量。每次调用getopt时,optind保存下个参数在argv中的索引(index)。如果找到一个选项,getopt会返回找到的选项字符,更新optind。如果选项有参数,将参数存到optarg,否则optarg为0。

(3). int opterr: 这个变量为非零时,getopt为”无效选项”或”缺少参数选项”输出错误信息。

(4). int optopt: 当发现无效选项字符时,getopt或返回'?'字符,或返回':'字符,并且optopt包含了所发现的无效选项字符。

getopt定义分为三种:

(1). 不带参数的选项。

(2). 必须带参数的选项:在选项后加一个冒号。

(3). 可选参数的选项:在选项后加两个冒号。

注意事项:

(1). 不带参数的选项可用连写。

(2). 选项不分先后顺序。

(3). 可选参数的选项与参数之间不能有空格。

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

CMakeLists.txt文件内容如下:

PROJECT(samples_cplusplus)
CMAKE_MINIMUM_REQUIRED(VERSION 3.0)

# 支持C++11
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -O2 -std=c11")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}  -g -Wall -O2 -std=c++11")

INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR})

FILE(GLOB samples ${PROJECT_SOURCE_DIR}/*.cpp)

FOREACH (sample ${samples})
	STRING(REGEX MATCH "[^/]+$" sample_file ${sample})
	STRING(REPLACE ".cpp" "" sample_basename ${sample_file})
	ADD_EXECUTABLE(test_${sample_basename} ${sample})
	TARGET_LINK_LIBRARIES(test_${sample_basename} pthread)
ENDFOREACH()

sample_getopt.cpp内容如下:

#include <iostream>
#include <unistd.h>

namespace {

void test1(int argc, char* argv[])
{
	// reference: http://man7.org/linux/man-pages/man3/getopt.3.html
	int flags = 0, opt = -1, nsecs = 0, tfnd = 0;
	while ((opt = getopt(argc, argv, "nt:")) != -1) {
		switch (opt) {
		case 'n':
			flags =1;
			break;
		case 't':
			nsecs = atoi(optarg);
			tfnd = 1;
			break;
		default:
			fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\n", argv[0]);
			exit(EXIT_FAILURE);
		}
	}
	
	fprintf(stdout, "flags = %d; tfnd = %d; nsec = %d; optind = %d\n", flags, tfnd, nsecs, optind);

	if (optind >= argc) {
		fprintf(stderr, "Expected argument after options\n");
		exit(EXIT_FAILURE);
	}

	fprintf(stdout, "name argument = %s\n", argv[optind]);

	exit(EXIT_SUCCESS);
}

int test2()
{
	// reference: https://stackoverflow.com/questions/10502516/how-to-call-correctly-getopt-function
	const char* argv[] = {"ProgramNameHere", "-f", "input.gmn", "-output.jpg"};
	int argc = sizeof(argv) / sizeof(argv[0]);
	std::cout<<"argc: "<<argc<<std::endl;
	for (int i = 0; i < argc; ++i) {
		//std::cout<<"argv: "<<argv[i]<<std::endl;
	}

	int c = -1;
	while ((c = getopt(argc, (char**)argv, "f:s:o:pw:h:z:t:d:a:b:?")) != -1) {
		std::cout<<"Option: "<<(char)c;
		if (optarg) {
			std::cout<<", argument: "<<optarg;
		}
		std::cout<<"\n";
	}

	return 0;
}

int test3(int argc, char* argv[])
{
	// reference: https://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html
	// Normally, getopt is called in a loop. When getopt returns -1, indicating no more options are present, the loop terminates.
	// A switch statement is used to dispatch on the return value from getopt. In typical use, each case just sets a variable that is used later in the program.
	// A second loop is used to process the remaining non-option arguments.
	int aflag = 0, bflag = 0, index = -1, c = -1;
	char* cvalue = nullptr;
	opterr = 0;
	
	while ((c = getopt(argc, argv, "abc:")) != -1) {
		switch (c) {
		case 'a':
			aflag = 1;
			break;
		case 'b':
			bflag = 1;
			break;
		case 'c':
			cvalue = optarg;
			break;
		case '?':
			if (optopt == 'c')
				fprintf(stderr, "Option -%c requires an argument.\n", optopt);
			else if (isprint(optopt))
				fprintf(stderr, "Unknown option '-%c'.\n", optopt);
			else
				fprintf(stderr, "Unknown option character '\\x%x'.\n", optopt);
			return 1;
		default:
			abort();
		}
	}		

	fprintf(stdout, "aflag = %d, bflag = %d, cvalue = %s\n", aflag, bflag, cvalue);

	for (index = optind; index < argc; ++index) {
		fprintf(stdout, "index: %d, Non-option argument: %s\n", index, argv[index]);
	}
	
	return 0;
}

} // namespace

int main(int argc, char* argv[])
{
	if (argc < 2) {
		fprintf(stderr, "the number of params must be greater than or equal to 2\n");
		return -1;
	}

	int flag = atoi(argv[1]);
	switch(flag) {
	case 1:
		fprintf(stdout, "start test 1:\n");
		test1(argc, argv);
		break;
	case 2:
		fprintf(stdout, "start test 2:\n");
		test2();
		break;
	case 3:
		fprintf(stdout, "start test 3:\n");
		test3(argc, argv);
		break;
	default:
		fprintf(stderr, "params error\n");
		break;
	}

	return 0;
}

build.sh内容如下:

#! /bin/bash

real_path=$(realpath $0)
dir_name=`dirname "${real_path}"`
echo "real_path: ${real_path}, dir_name: ${dir_name}"

new_dir_name=${dir_name}/build
mkdir -p ${new_dir_name}
cd ${new_dir_name}
cmake ..
make

cd -

run_getopt.sh内容如下:

#! /bin/bash

real_path=$(realpath $0)
dir_name=`dirname "${real_path}"`
echo "real_path: ${real_path}, dir_name: ${dir_name}"

echo "test1:"
${dir_name}/build/test_sample_getopt 9 # params error
${dir_name}/build/test_sample_getopt 1 # flags = 0; tfnd = 0; nsec = 0; optind = 1
${dir_name}/build/test_sample_getopt 1 -b # invalid option -- 'b'
${dir_name}/build/test_sample_getopt 1 -x YYY # invalid option -- 'x'
${dir_name}/build/test_sample_getopt 1 -vZZZ # invalid option -- 'v'
${dir_name}/build/test_sample_getopt 1 -t 999 -n Jim # flags = 1; tfnd = 1; nsec = 999; optind = 4
${dir_name}/build/test_sample_getopt 1 -t888 -nSom # invalid option -- 'S'
${dir_name}/build/test_sample_getopt 1 -t6666 # flags = 0; tfnd = 1; nsec = 6666; optind = 2
${dir_name}/build/test_sample_getopt 1 -nant -t555 # invalid option -- 'a'
${dir_name}/build/test_sample_getopt 1 -n222 -t111 # invalid option -- '2'

echo -e "\n\ntest2:"
${dir_name}/build/test_sample_getopt 2
# argc: 4
# Option: f, argument: input.gmn
# Option: o, argument: utput.jpg

echo -e "\n\ntest3:"
${dir_name}/build/test_sample_getopt 3
# aflag = 0, bflag = 0, cvalue = (null)
# index: 1, Non-option argument: 3
${dir_name}/build/test_sample_getopt 3 -a -b
# aflag = 1, bflag = 1, cvalue = (null)
# index: 3, Non-option argument: 3 
${dir_name}/build/test_sample_getopt 3 -ab
# aflag = 1, bflag = 1, cvalue = (null)
# iindex: 2, Non-option argument: 3
${dir_name}/build/test_sample_getopt 3 -c foo
# aflag = 0, bflag = 0, cvalue = foo
# index: 3, Non-option argument: 3
${dir_name}/build/test_sample_getopt 3 -cfoo
# aflag = 0, bflag = 0, cvalue = foo
# index: 2, Non-option argument: 3
${dir_name}/build/test_sample_getopt 3 arg1
# aflag = 0, bflag = 0, cvalue = (null)
# index: 1, Non-option argument: 3
# index: 2, Non-option argumnet: arg1
${dir_name}/build/test_sample_getopt 3 -a arg1
# aflag = 1, bflag = 0, cvalue = (null)
# index: 2, Non-option argument: 3
# index: 3, Non-option argument: arg1
${dir_name}/build/test_sample_getopt 3 -c foo arg1
# aflag = 0, bflag = 0, cvalue = foo
# index: 3, Non-option argument: 3
# index: 4, Non-option argument: arg1
${dir_name}/build/test_sample_getopt 3 -a -- -b
# aflag = 1, bflag = 0, cvalue = (null)
# index: 3, Non-option argument: 3
# index: 4, Non-option argument: -b
${dir_name}/build/test_sample_getopt 3 -a -
# aflag = 1, bflag = 0, cvalue = (null)
# index: 2, Non-option argument: 3
# index: 3, Non-option argument: -

执行过程:首先执行build.sh,然后再执行run_getopt.sh即可。

GitHubhttps://github.com/fengbingchun/Linux_Code_Test  

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux下getopt函数的使用 的相关文章

  • /sys/device/ 和 dmidecode 报告的不同 CPU 缓存大小

    我正在尝试获取系统中不同缓存级别的大小 我尝试了两种技术 a 使用 sys device 中的信息 这是输出 cat sys devices system cpu cpu0 cache index1 size 32K cat sys dev
  • 如何从 C++ 程序中重新启动 Linux?

    我有一个 Qt 4 GUI 我需要在下拉菜单中提供一个选项 允许用户选择重新启动计算机 我意识到这对于以其他方式重新启动计算机的能力来说似乎是多余的 但选择需要保留在那里 我尝试使用 system 来调用以下内容 suid root she
  • 来自守护程序的错误响应:加入会话密钥环:创建会话密钥:超出磁盘配额

    我尝试在我的服务器上安装 docker 使用本教程 https docs docker com install linux docker ce ubuntu 我想远程运行 docker 镜像并使用 portainer Web 界面来管理一切
  • 为什么 fork 炸弹没有使 android 崩溃?

    这是最简单的叉子炸弹 我在许多 Linux 发行版上执行了它 但它们都崩溃了 但是当我在 android 终端中执行此操作时 即使授予后也没有效果超级用户权限 有什么解释为什么它没有使 Android 系统崩溃吗 一句话 ulimit Li
  • grep 排除文件的数组参数

    我想从我的文件中排除一些文件grep命令 为此我使用参数 exclude excluded file ext 为了更容易阅读 我想使用包含排除文件的 bash 数组 EXCLUDED FILES excluded file ext 然后将
  • vmsplice() 和 TCP

    在原来的vmsplice 执行 有人建议 http lwn net Articles 181169 如果您的用户态缓冲区是管道中可容纳的最大页面数的 2 倍 则缓冲区后半部分成功的 vmsplice 将保证内核使用缓冲区的前半部分完成 但事
  • 找不到包“gdk-pixbuf-2.0”

    我正在尝试在 Amazon Linux 发行版实例上构建 librsvg 我已经通过 yum 安装了大部分依赖项 其中一些在实例上启用的默认 yum 存储库中不可用 因此必须从头开始构建它们 我已经走了很远 但还停留在最后一点 跑步时sud
  • 执行命令而不将其保留在历史记录中[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 在进行软件开发时 经常需要在命令行命令中包含机密信息 典型示例是将项目部署到服务器的凭据设置为环境变量 当我不想将某些命令存储在命令历史记
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • linux-x64 二进制文件无法在 linuxmusl-x64 平台上使用错误

    我正在安装Sharp用于使用 package json 的 Nodejs 项目的 docker 映像上的映像压缩包 当我创建容器时 我收到有关 Sharp 包的以下错误 app node modules sharp lib libvips
  • 如何在 Ubuntu 中创建公共 HTML 文件夹?

    简单的问题 但由于某种原因我无法在谷歌上找到确切的答案 我在 Slicehost 上安装了全新的 Ubuntu 并且想在我的主目录中为包含一堆静态 HTML 文件的简单网站创建一个公共目录 我该怎么做呢 只是打字的问题吗mkdir publ
  • 如何在linux中以编程方式获取dir的大小?

    我想通过 C 程序获取 linux 中特定目录的确切大小 我尝试使用 statfs path struct statfs 但它没有给出确切的大小 我也尝试过 stat 但它返回任何目录的大小为 4096 请建议我如何获取 dir 的确切大小
  • 如何阻止ubuntu在使用apt安装或更新软件包时弹出“Daemons using outdatedlibraries”? [关闭]

    Closed 这个问题是与编程或软件开发无关 help closed questions 目前不接受答案 我最近新安装了 Ubuntu 22 04 LTS 我发现每次使用 apt 安装或更新软件包时 它都会询问我有关Which servic
  • 从 ttyUSB0 写入和读取,无法得到响应

    我对 Linux tty 不太有经验 我的环境是带有丰富 USB 串行的 Raspbian 什么有效 stty F dev ttyUSB0 38400 cu l dev ttyUSB0 s 38400 cu to dev ttyUSB0作品
  • 使用循环在 C 中管道传输两个或多个 shell 命令

    我正在尝试执行ls wc l通过 C 语言程序 而不是使用命令行 这是我当前的工作代码 int main int pfds 2 pipe pfds pid t pid fork if pid 0 The child process clos
  • 如何让R使用所有处理器?

    我有一台运行 Windows XP 的四核笔记本电脑 但查看任务管理器 R 似乎一次只使用一个处理器 如何让 R 使用全部四个处理器并加速我的 R 程序 我有一个基本系统 我使用它在 for 循环上并行化我的程序 一旦您了解需要做什么 此方
  • .net-core:ILDASM / ILASM 的等效项

    net core 是否有相当于 ILDASM ILASM 的功能 具体来说 我正在寻找在 Linux 上运行的东西 因此为什么是 net core ildasm 和 ilasm 工具都是使用此存储库中的 CoreCLR 构建的 https
  • Intel 上的 gcc 中的 _mm_pause 用法

    我参考过这个网页 https software intel com en us articles benefitting power and performance sleep loops https software intel com
  • 如何查找哪个 Yocto 项目配方填充图像根文件系统上的特定文件

    我经常与 Yocto 项目合作 一个常见的挑战是确定文件为何 或来自什么配方 包含在 rootfs 中 这有望从构建系统的环境 日志和元数据中得出 理想情况下 一组命令将允许将文件链接回源 即配方 我通常的策略是对元数据执行搜索 例如gre
  • 绕过 dev/urandom|random 进行测试

    我想编写一个功能测试用例 用已知的随机数值来测试程序 我已经在单元测试期间用模拟对其进行了测试 但我也希望用于功能测试 当然不是全部 最简单的方法是什么 dev urandom仅覆盖一个进程 有没有办法做类似的事情chroot对于单个文件并

随机推荐

  • 【H5】 svg画扇形饼图

    H5 svg画扇形饼图 效果图如下 封装代码如下 代码内有详细注解哦
  • Android 获取网络速度

    一 效果图 一 通过wifimanager来获取WiFi的当前速度状态 WifiManager wm WifiManager NetworkSignalDetectionActivity this getApplicationContext
  • 第二次用烤箱做了面包

    可松做成了法棍 味道还不错 img http dl iteye com upload attachment 314370 296dbfa1 491e 3df9 93c9 77d709a25b38 jpg img
  • get和post区别

    1 GET请求在URL中传送的参数是有长度限制的 而POST没有 2 GET相对于POST来说不安全 因为参数直接暴露在URL上 所以不能用来传递敏感信息 而POST数据不会显示在URL中 是放在Request body中 3 对参数的数据
  • 有关 sscanf 和 sprintf 的用法

    sscanf 的用法 用法 int sscanf const char str const char format 功能 从字符串读取格式化输入 返回值 如果成功 该函数返回成功匹配和赋值的个数 如果到达文件末尾或发生读错误 则返回 EOF
  • C语言单向循环链表的建立

    1 头文件 include
  • 【数学建模】线性规划模型基本原理与案例分享

    1 1 线性规划问题 在人们的生产实践中 经常会遇到如何利用现有资源来安排生产 以取得最大经济效益的问题 此类问题构成了运筹学的一个重要分支 数学规划 而线性规划 Linear Programming 简记LP 则是数学规划的一个重要分支
  • 国产CPU对比

    关于国产CPU 龙芯 飞腾 鲲鹏 海光 申威 兆芯 CPU 是计算机系统的核心和大脑 n CPU 即中央处理器是计算机的运算和控制核心 其功能主要是解释计算机指令以及处理计算机软件中的数据 CISC实际上是以增加处理器本身复杂度作为代价 去
  • Jenkins系列:3、wsl/ubuntu安装Jenkins及Jenkins构建可交叉编译的go程序

    Jenkins系列 3 wsl ubuntu安装Jenkins及Jenkins构建可交叉编译的go程序 文章目录 Jenkins系列 3 wsl ubuntu安装Jenkins及Jenkins构建可交叉编译的go程序 1 前言 2 wsl
  • 数组去重合并

    let arrA id 1 name name1 id 2 name name2 let arrB id 1 name name3 id 3 name name4 function concatArr arrA arrB 只需要拿到A
  • ANDROID版本号和版本名称的重要性介绍

    转载请注明出处http blog csdn net y150481863 article details 41249159 来自 http blog csdn net y150481863 当我们在刚开始学习ANDROID的时候 可能不会过
  • DVWA安装配置教程

    原文传送门 http www cnblogs com yaochc p 5049832 html DVWA 安装教程 1 直接下载WampServer 免去了需要安装apache php mysql的服务器软件的痛苦 一体集成 相当于安装了
  • CSRF漏洞详细说明

    CSRF漏洞详细说明 通常情况下 有三种方法被广泛用来防御CSRF攻击 验证token 验证HTTP请求的Referer 还有验证XMLHttpRequests里的自定义header 鉴于种种原因 这三种方法都不是那么完美 各有利弊 二 C
  • H.265/HEVC编码结构

    H 265 HEVC编码结构 为了增强各种应用下操作的灵活性以及数据损失的鲁棒性 H 265 HEVC在编解码的设计上添加了多种新的语法结构 相较于以往的视频编码标准 如H 264 AVC 这种新的语法架构使得H 265 HEVC在压缩效率
  • linux虚拟机可以ping通,但是无法socket连接

    场景 两台windows各开一台Linux虚拟机 通过路由器组网 分配桥接地址 出现电脑之间ping不通 socket不通怎么办 答案 1 关掉windows防火墙 任何阻止联网的行为统统取消 2 关掉linux防火墙 对 etc seli
  • 狂飙!GPT-4最新20+个应用案例集锦,附视频

    编者按 自OpenAI于3月15日重磅推出GPT 4 一石激起千层浪 全球开发者 创业者们迅速尝试了各种形形色色的场景应用 来体验它的极限 游戏 编程 客户关系 营销 财务 家庭生活 饮食 文学艺术创作等等不一而足 笔者从中筛选了23款基于
  • HandlerAdapter

    HandleAdapter HandlerAdapter的功能实际就是执行我们的具体的Controller Servlet或者HttpRequestHandler中的方法 类结构如下 1 SimpleServletHandlerAdapte
  • 【实战】将多个不规则多级表头的工作表合并为一个规范的一维表数据结果表...

    最近在项目里 有个临时的小需求 需要将一些行列交叉结构的表格进行汇总合并 转换成规范的一维表数据结构进行后续的分析使用 从一开始想到的使用VBA拼接字符串方式 完成PowerQuery的M语言查询字符串 然后转换成使用插件方式来实现相同功能
  • Unity-AR 简介

    Unity AR 简介 现有Unity AR Sdk ARKit 苹果推出的AR开发平台 ARCore Google 推出的增强现实 SDK ARFoundation ARFoundation是ARKit XR插件和ARCore XR插件
  • Linux下getopt函数的使用

    getopt为解析命令行参数函数 它是Linux C库函数 使用此函数需要包含系统头文件unistd h getopt函数声明如下 int getopt int argc char const argv const char optstri