/usr/bin/time 使用记录和参数解析(一)

/usr/bin/time 使用记录和参数解析(一)

前言

参考

$ /usr/bin/time -V
GNU time 1.7

源码

wget https://ftp.gnu.org/gnu/time/time-1.7.tar.gz 
tar -zxf time-1.7.tar.gz
./configure
make

使用

一个文件读写测试案例

$ /usr/bin/time -v ./directIo > out2.log
        Command being timed: "./directIo"
        User time (seconds): 0.04
        System time (seconds): 1.24
        Percent of CPU this job got: 52%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.48
        Average shared text size (kbytes): 0
        Average unshared data size (kbytes): 0
        Average stack size (kbytes): 0
        Average total size (kbytes): 0
        Maximum resident set size (kbytes): 1524
        Average resident set size (kbytes): 0
        Major (requiring I/O) page faults: 0
        Minor (reclaiming a frame) page faults: 69
        Voluntary context switches: 9989
        Involuntary context switches: 1
        Swaps: 0
        File system inputs: 10000
        File system outputs: 10704
        Socket messages sent: 0
        Socket messages received: 0
        Signals delivered: 0
        Page size (bytes): 4096
        Exit status: 0

参数解析代码阅读

getopt.h

#ifndef ANT_GETOPT
#define ANT_GETOPT
#ifdef __cplusplus
// 让编译器以处理 C 语言代码的方式来处理修饰的 C++ 代码
extern "C" {
#endif

struct option {
    const char *name;
    int has_arg;
    int *flag;
    int val;
};

#define no_argument       0
#define required_argument 1
#define optional_argument 2

extern char *optarg;
extern int optind, opterr, optopt;

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

int getopt_long(int argc, char * const argv[],
                  const char *optstring,
                  const struct option *longopts, int *longindex);

int getopt_long_only(int argc, char * const argv[],
            const char *optstring,
            const struct option *longopts, int *longindex);


#ifdef __cplusplus
}
#endif
#endif

getopt.c


#include "getopt.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 如果某个选项有参数,用于获取传入的参数值
char *optarg = NULL;
// argv 的当前索引值。循环结束后,剩下的字串视为操作数,在argv[optind]至argv[argc-1]中可以找到
int optind = 0;
// 指向选择参数(不包括-, --), 用于处理类似 -abc 的连续短选项 
static char *nextchar;
// 出错原因
int opterr = 1;
// 包含了所发现的无效选项字符
int optopt = '?';

static enum {
    /* 当看到第一个非选项时停止选项处理:POSIXLY_CORRECT 环境变量,或者开头使用+ */
    REQUIRE_ORDER,
    /* 默认,会打乱顺序,非选项都会放在后面*/
    PERMUTE,

    RETURN_IN_ORDER
} ordering;

static char *my_index(const char *str, int chr)
{
    while (*str) {
        if (*str == chr)
            return (char *)str;
        str++;
    }
    return 0;
}

// 第一个非选项的所在索引
static int first_nonopt;
// 最后一个非选项所在索引
static int last_nonopt;

// Bash 2.0有一个环境变量,其中包含指示argv元素的标志,不应被视为参数
static const char *nonoption_flags;
static int nonoption_flags_len;

static void exchange(char **argv)
{
    int bottom = first_nonopt;
    int middle = last_nonopt;
    int top = optind;
    char *tem;

    /* Exchange the shorter segment with the far end of the longer segment.
       That puts the shorter segment into the right place.
       It leaves the longer segment in the right place overall,
       but it consists of two parts that need to be swapped next.  */

    while (top > middle && middle > bottom) {
        if (top - middle > middle - bottom) {
            /* Bottom segment is the short one.  */
            int len = middle - bottom;
            register int i;

            /* Swap it with the top part of the top segment.  */
            for (i = 0; i < len; i++) {
                tem = argv[bottom + i];
                argv[bottom + i] = argv[top - (middle - bottom) + i];
                argv[top - (middle - bottom) + i] = tem;
            }
            /* Exclude the moved bottom segment from further swapping.  */
            top -= len;
        } else {
            /* Top segment is the short one.  */
            int len = top - middle;
            register int i;

            /* Swap it with the bottom part of the bottom segment.  */
            for (i = 0; i < len; i++) {
                tem = argv[bottom + i];
                argv[bottom + i] = argv[middle + i];
                argv[middle + i] = tem;
            }
            /* Exclude the moved top segment from further swapping.  */
            bottom += len;
        }
    }

    /* Update records for the slots the non-options now occupy.  */

    first_nonopt += (optind - last_nonopt);
    last_nonopt = optind;
}

static char *posixly_correct;

static const char *_getopt_initialize(const char *optstring)
{

    first_nonopt = last_nonopt = optind = 1;

    nextchar = NULL;
    // 测试环境为NULL
    posixly_correct = getenv("POSIXLY_CORRECT");

    if (optstring[0] == '-') {
        ordering = RETURN_IN_ORDER;
        ++optstring;
    } else if (optstring[0] == '+') {
        ordering = REQUIRE_ORDER;
        ++optstring;
    } else if (posixly_correct != NULL)
        ordering = REQUIRE_ORDER;
    else
        ordering = PERMUTE;

    if (posixly_correct == NULL) {
        char var[100];
        sprintf(var, "_%d_GNU_nonoption_argv_flags_", getpid());
        nonoption_flags = getenv(var);
        // 测试环境为NULL
        if (nonoption_flags == NULL)
            nonoption_flags_len = 0;
        else
            nonoption_flags_len = strlen(nonoption_flags);
    }

    return optstring;
}

int _getopt_internal(int argc, char *const *argv, const char *optstring,
                     const struct option *longopts, int *longind, int long_only)

{
    optarg = NULL;
    /* Don't scan argv[0], 同时做一些初始化工作  */
    if (optind == 0) {
        optstring = _getopt_initialize(optstring);
        optind = 1;
    }

// 判断是否为选择格式:不以-开头,或者只有-
#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \
    || (optind < nonoption_flags_len && nonoption_flags[optind] == '1'))


    // 如果不是连续的短选项处理,则获取下一个的选项参数
    if (nextchar == NULL || *nextchar == '\0') {
        /* Advance to the next ARGV-element.  */

        /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
           moved back by the user (who may also have changed the arguments).  */
        if (last_nonopt > optind)
            last_nonopt = optind;
        if (first_nonopt > optind)
            first_nonopt = optind;

        if (ordering == PERMUTE) {
            /* If we have just processed some options following some non-options,
               exchange them so that the options come first.  */

            if (first_nonopt != last_nonopt && last_nonopt != optind)
                exchange((char **)argv);
            else if (last_nonopt != optind)
                first_nonopt = optind;

            // 跳过非选择参数
            while (optind < argc && NONOPTION_P)
                optind++;
            last_nonopt = optind;
        }

        /* The special ARGV-element `--' means premature end of options.
           Skip it like a null option,
           then exchange with previous non-options as if it were an option,
           then skip everything else like a non-option.  */

        if (optind != argc && !strcmp(argv[optind], "--")) {
            optind++;

            if (first_nonopt != last_nonopt && last_nonopt != optind)
                exchange((char **)argv);
            else if (first_nonopt == last_nonopt)
                first_nonopt = optind;
            last_nonopt = argc;

            optind = argc;
        }

        // 命令行处理完
        if (optind == argc) {
            // 如果存在非选择参数,则让程序自己处理
            if (first_nonopt != last_nonopt)
                optind = first_nonopt;
            return EOF;
        }

        if (NONOPTION_P) {
            // 遇到一个非选项参数,且是REQUIRE_ORDER 则不在处理
            if (ordering == REQUIRE_ORDER)
                return EOF;
            optarg = argv[optind++];
            return 1;
        }

        // 找到选项参数,跳过 - 或 --
        nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-'));
    }

    // getopt_long_only 长选项可以不用输入两个--, 、
    if (longopts != NULL && (argv[optind][1] == '-' || 
        (long_only && (argv[optind][2] || !my_index(optstring, argv[optind][1]))))) {
        char *nameend;
        const struct option *p;
        const struct option *pfound = NULL;
        int exact = 0;
        int ambig = 0;
        int indfound;
        int option_index;

        // 解析出参数名
        for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
            /* Do nothing.  */;

        // 这里要求long_options 最后一个元素 全为0,类似字符串的判断
        for (p = longopts, option_index = 0; p->name; p++, option_index++) {
            if (!strncmp(p->name, nextchar, nameend - nextchar)) {
                // 发现前缀部分相同
                if (nameend - nextchar == strlen(p->name)) {
                    /* 完全一致  */
                    pfound = p;
                    indfound = option_index;
                    exact = 1;
                    break;
                } else if (pfound == NULL) {
                    // 如果只能推测出一个参数,就能往下继续执行
                    pfound = p;
                    indfound = option_index;
                } else {
                    /* 发现多个前缀相同 */
                    ambig = 1;
                }
            }
        }
            
        // 这里表示如果有多个前缀相同,但不存在精准匹配则报错
        if (ambig && !exact) {
            if (opterr)
                fprintf(stderr, ("%s: option `%s' is ambiguous\n"),
                        argv[0], argv[optind]);
            nextchar += strlen(nextchar);
            optind++;
            optopt = 0;
            return '?';
        }

        if (pfound != NULL) {
            option_index = indfound;
            optind++;
            if (*nameend) {
                // *nameend为‘=’, 即--prefix=(parameter)
                if (pfound->has_arg)
                    optarg = nameend + 1;
                else {
                    // 不准携带参数,却带了=则报错
                    if (opterr)
                        if (argv[optind - 1][1] == '-')
                            /* --option */
                            fprintf(stderr,
                                    ("%s: option `--%s' doesn't allow an argument\n"),
                                    argv[0], pfound->name);
                        else
                            /* +option or -option */
                            fprintf(stderr,
                                    ("%s: option `%c%s' doesn't allow an argument\n"),
                                    argv[0], argv[optind - 1][0], pfound->name);

                    nextchar += strlen(nextchar);

                    optopt = pfound->val;
                    return '?';
                }
            } else if (pfound->has_arg == 1) {
                // 必须有参数
                if (optind < argc)
                    optarg = argv[optind++];
                else {
                    if (opterr)
                        fprintf(stderr,
                                ("%s: option `%s' requires an argument\n"),
                                argv[0], argv[optind - 1]);
                    nextchar += strlen(nextchar);
                    optopt = pfound->val;
                    return optstring[0] == ':' ? ':' : '?';
                }
            }
            nextchar += strlen(nextchar);
            if (longind != NULL)
                *longind = option_index;

            // flag=NULL时,返回val;不为空时,*flag=val,返回0 
            if (pfound->flag) {
                *(pfound->flag) = pfound->val;
                return 0;
            }
            return pfound->val;
        }

        // 选项不存在
        if (!long_only || argv[optind][1] == '-' || my_index(optstring, *nextchar) == NULL) {
            if (opterr) {
                if (argv[optind][1] == '-')
                    /* --option */
                    fprintf(stderr, ("%s: unrecognized option `--%s'\n"),
                            argv[0], nextchar);
                else
                    /* +option or -option */
                    fprintf(stderr, ("%s: unrecognized option `%c%s'\n"),
                            argv[0], argv[optind][0], nextchar);
            }
            // 类似置空
            nextchar = (char *)"";
            optind++;
            optopt = 0;
            return '?';
        }
    }
    
    // 获取短选项
    {
        char c = *nextchar++;
        char *temp = my_index(optstring, c);

        /* Increment `optind' when we start to process its last character.  */
        if (*nextchar == '\0')
            ++optind;

        // 如果没有找到,选项不能设置为 ':'
        if (temp == NULL || c == ':') {
            if (opterr) {
                if (posixly_correct)
                    /* 1003.2 specifies the format of this message.  */
                    fprintf(stderr, ("%s: illegal option -- %c\n"),  argv[0], c);
                else
                    fprintf(stderr, ("%s: invalid option -- %c\n"),  argv[0], c);
            }
            // 设置非法选项
            optopt = c;
            return '?';
        }
        // 如果该选项可以有参数
        if (temp[1] == ':') {
            if (temp[2] == ':') {
                // 可选参数格式:-n 或 -n(parameter),但不能为 -n (parameter)
                if (*nextchar != '\0') {
                    optarg = nextchar;
                    optind++;
                } else
                    optarg = NULL;
                nextchar = NULL;
            } else {
                // 必须带有选项为:-p 的形式 -p(parameter) 或 -p (parameter)
                if (*nextchar != '\0') {
                    // 参数形式为 -p(parameter)
                    optarg = nextchar;
                    optind++;
                } else if (optind == argc) {
                    // 没有参数
                    if (opterr) {
                        /* 1003.2 specifies the format of this message.  */
                        fprintf(stderr,("%s: option requires an argument -- %c\n"),  argv[0], c);
                    }
                    optopt = c;
                    if (optstring[0] == ':')
                        c = ':';
                    else
                        c = '?';
                } else {
                    // 参数形式为 -p (parameter)
                    optarg = argv[optind++];
                }
                nextchar = NULL;
            }
        }
        return c;
    }
}

int getopt(int argc, char *const *argv, const char *optstring)
{
    return _getopt_internal(argc, argv, optstring,
                            (const struct option *)0,
                            (int *)0,
                            0);
}

int getopt_long(int argc,
                char *const *argv,
                const char *options,
                const struct option *long_options,
                int *opt_index)

{
    return _getopt_internal(argc, argv, options, long_options, opt_index, 0);
}

/* Like getopt_long, but '-' as well as '--' can indicate a long option.
   If an option that starts with '-' (not '--') doesn't match a long option,
   but does match a short option, it is parsed as a short option
   instead.  */

int getopt_long_only(int argc,
                     char *const *argv,
                     const char *options,
                     const struct option *long_options,
                     int *opt_index)

{
    return _getopt_internal(argc, argv, options, long_options, opt_index, 1);
}

测试代码

main.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "getopt.h"
// #include <unistd.h>
// #include <getopt.h>

int main1(int argc, char **argv)
{
    int c;
    int digit_optind = 0;

    while (1) {
        int this_option_optind = optind ? optind : 1;

        c = getopt(argc, argv, "abc:d:0123456789");
        if (c == EOF)
            break;

        switch (c) {
        case '0' ... '9':
            if (digit_optind != 0 && digit_optind != this_option_optind)
                printf("digits occur in two different argv-elements.\n");
            digit_optind = this_option_optind;
            printf("option %c\n", c);
            break;

        case 'a':
            printf("option a\n");
            break;

        case 'b':
            printf("option b\n");
            break;

        case 'c':
            printf("option c with value `%s'\n", optarg);
            break;

        case '?':
            printf("invalid opt: %c\n",optopt);
            break;

        default:
            printf("?? getopt returned character code 0%o ??\n", c);
        }
    }

    if (optind < argc) {
        printf("non-option ARGV-elements: ");
        while (optind < argc)
            printf("%s ", argv[optind++]);
        printf("\n");
    }

    exit(0);
}

int main(int argc, char **argv)
{
    int c;
    int digit_optind = 0;

    while (1) {
        int this_option_optind = optind ? optind : 1;
        int option_index = 0;
        static struct option long_options[] =
            {
                {"add", 1, 0, 0},
                {"append", 0, 0, 0},
                {"delete", 1, 0, 0},
                {"verbose", 0, 0, 0},
                {"create", 0, 0, 0},
                {"file", 1, 0, 0},
                {0, 0, 0, 0}};

        c = getopt_long_only(argc, argv, "abc:d:0123456789",
                        long_options, &option_index);
        if (c == EOF)
            break;

        switch (c) {
        case 0:
            printf("option %s", long_options[option_index].name);
            if (optarg)
                printf(" with arg %s", optarg);
            printf("\n");
            break;

        case '0' ... '9':
            if (digit_optind != 0 && digit_optind != this_option_optind)
                printf("digits occur in two different argv-elements.\n");
            digit_optind = this_option_optind;
            printf("option %c\n", c);
            break;

        case 'a':
            printf("option a\n");
            break;

        case 'b':
            printf("option b\n");
            break;

        case 'c':
            printf("option c with value `%s'\n", optarg);
            break;

        case 'd':
            printf("option d with value `%s'\n", optarg);
            break;

        case '?':
            break;

        default:
            printf("?? getopt returned character code 0%o ??\n", c);
        }
    }

    if (optind < argc) {
        printf("non-option ARGV-elements: ");
        while (optind < argc)
            printf("%s ", argv[optind++]);
        printf("\n");
    }

    exit(0);
}

Makefile:

main : main.c getopt.c
	gcc -g -o $@ $^

clean:
	rm -rf main
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值