int getopt(int argc, char * const argv[], const char *optstring); //getopt专属的全局变量 extern char *optarg; extern int optind, opterr, optopt;
前两个参数就是main的两个参数,而optstring是由选项字母组成的字符串。如果optstring中一个选项后面有冒号:,说明这个选项会有参数存在,并且这个参数由optarg指向。而optind表示下一个参数的下标,注意是下一个,不是当前这个。
If an option was successfully found, then getopt() returns the option character. If all command-line options have been parsed, then getopt() returns -1.
实现一个有选项的mydate指令
/* y输出年份 m输出月份 d输出日期 H输出小时 M输出分钟 S输出秒 */ int main(int argc, char *argv[]) { time_t stamp = time(NULL); struct tm *tm = localtime(&stamp); int c, index = 0; char fmt[FMTSTRSIZE] = {0}; FILE *tmp = NULL; FILE *fp[10]; while (1) { c = getopt(argc, argv, "-H:MSy:md"); //optstring的第一个字符是-,那么如果遇到非选项时 //返回的都是1 //同时这里的H和y都需要参数 if (c < 0) break; switch(c) { case 'y': //如果参数是2则输出年份后两位 if (strcmp(optarg, "2") == 0) strcat(fmt, "%y "); //参数是4则输出4位 else if (strcmp(optarg, "4") == 0) strcat(fmt, "%Y "); else fprintf(stderr, "Invalid argument %s", optarg); break; case 'm': strcat(fmt, "%m "); break; case 'd': strcat(fmt, "%d "); break; case 'H': //参数12输出12小时制时间 if (strcmp(optarg, "12") == 0) strcat(fmt, "%I(%P) "); //参数24输出24小时制时间 else if (strcmp(optarg, "24") == 0) strcat(fmt, "%H "); else fprintf(stderr, "Invalid argument %s", optarg); break; case 'M': strcat(fmt, "%M "); break; case 'S': strcat(fmt, "%S "); break; case 1: //如果有选项是文件,则将日期输出到文件中 tmp = fopen(argv[optind - 1], "w"); if (tmp == NULL) { perror("fopen()"); tmp = stdout; //不是文件则默认输出到stdout } fp[index++] = tmp; break; default: break; } } strcat(fmt, "\n"); char timestr[TIMESTRSIZE]; strftime(timestr, TIMESTRSIZE, fmt, tm); for (int i = 0; i < index; i++) { fputs(timestr, fp[i]); fclose(fp[i]); } exit(0); }
还有个可以分析长格式的版本
int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);
环境变量是一系列name=value形式的字符串。
环境变量是用来定义系统运行环境的一些参数,比如每个用户不同的家目录(HOME)、邮件存放位置(MAIL)等。例如Windows和DOS操作系统中的path环境变量,当要求系统运行一个程序而没有告诉它程序所在的完整路径时,系统除了在当前目录下面寻找此程序外,还应到path中指定的路径去找。用户通过设置环境变量,来更好的运行进程。
char *getenv(const char *name);
传入一个name,返回一个value
int setenv(const char *name, const char *value, int overwrite);
用于改变或添加环境变量值。如果name不存在则添加,存在则是改变。如果overwrite是真则用现在的覆盖之前的,如果是假则保留原来的不进行覆盖
int putenv(char *string);
用于改变或添加环境变量值。与setenv的区别是传入的string是name=value的格式,如果name不存在则添加,否则修改成value
long sum[1000];
使此变量存放在非初始化数据段中。假设要通过递归找寻一个数,一层一层的向下递归找到后其实不用再一层一层的返回。可以用类似于goto的操作直接返回的起点,可是goto不能跨函数,可以使用setjmp和longjmp
setjmp函数设置返回点,保存调用函数的栈环境于env中(相当于保护现场)。longjmp的作用是使用setjmp保存在env中的栈环境信息返回到setjmp的位置,也就是当执行longjmp时程序又回到setjmp处(相当于恢复现场)
int setjmp(jmp_buf env);
设置跳转点时返回的是0,如果是从longjmp跳回来的返回的就是非0。这是一种执行一次返回两次的函数
void longjmp(jmp_buf env, int val);
#include <stdio.h> #include <stdlib.h> #include <setjmp.h> static jmp_buf sv; static void a(); static void b(); static void c(); int main() { printf("%s():Begin\n", __FUNCTION__); printf("%s():Call a()\n", __FUNCTION__); a(); printf("%s():a() returned\n", __FUNCTION__); printf("%s():End\n", __FUNCTION__); exit(0); } static void a() { int ret; printf("%s():Begin\n", __FUNCTION__); ret = setjmp(sv); if (ret == 0) { printf("%s():Call b()\n", __FUNCTION__); b(); printf("%s():b() returned\n", __FUNCTION__); } else { printf("%s():Junmped back here with code %d\n", __FUNCTION__, ret); } printf("%s():End\n", __FUNCTION__); } static void b() { printf("%s():Begin\n", __FUNCTION__); printf("%s():Call c()\n", __FUNCTION__); c(); printf("%s():c() returned\n", __FUNCTION__); printf("%s():End\n", __FUNCTION__); } static void c() { printf("%s():Begin\n", __FUNCTION__); printf("%s():Jump now!\n", __FUNCTION__); longjmp(sv, 6); printf("%s():End\n", __FUNCTION__); }
学了这章可以实现自己的ulimit指令
获得、设置资源的限制
int getrlimit(int resource, struct rlimit *rlim);
int setrlimit(int resource, const struct rlimit *rlim);
rlimit结构体如下:
struct rlimit { rlim_t rlim_cur; /* Soft limit */ rlim_t rlim_max; /* Hard limit (ceiling for rlim_cur) */ };
这里分为硬限制和软限制。普通用户可以对软限制进行升高降低,但是不能高过硬限制;普通用户只能降低硬限制,不能提高。root可以升高、降低软限制,同样不能高过硬限制;root也可以升高、降低硬限制。