Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 使用getopt根据选项标志的顺序更改程序的行为_C_Unix_Command - Fatal编程技术网

C 使用getopt根据选项标志的顺序更改程序的行为

C 使用getopt根据选项标志的顺序更改程序的行为,c,unix,command,C,Unix,Command,我正在用C编写一个cat命令克隆,当我更改选项标志的顺序时,我会有奇怪的行为 -s选项标志挤压双倍行距的行 -n选项标记对从1开始的每一行进行编号 我已通过以下方式检查了运行程序的差异: $ diff <(./myCat -s spaces.txt) <(cat -s spaces.txt) no difference $ diff <(./myCat -n spaces.txt) <(cat -n spaces.txt) no difference $ diff &

我正在用C编写一个cat命令克隆,当我更改选项标志的顺序时,我会有奇怪的行为

-s
选项标志挤压双倍行距的行

-n
选项标记对从
1
开始的每一行进行编号

我已通过以下方式检查了运行程序的差异:

$ diff <(./myCat -s spaces.txt) <(cat -s spaces.txt)
no difference

$ diff <(./myCat -n spaces.txt) <(cat -n spaces.txt)
no difference

$ diff <(./myCat -ns spaces.txt) <(cat -ns spaces.txt)
no difference

这是因为getopt中的optstring:

int-getopt(int-argc,char*const-argv[],const-char*optstring);
从手册页上看,optstring的行为是:

optstring是包含合法选项的字符串 人物。如果这样的字符后跟冒号,则 选项需要一个参数,因此getopt()将指针放在 同一argv元素中的以下文本,或 在optarg中的argv元素之后。两个冒号表示一个选项 获取可选参数;如果当前argv中有文本- 元素(即,与选项名称本身相同的单词,例如 例如,“-oarg”),则返回optarg,否则返回 optarg设置为零

下面的语句表示只有
s
需要参数:

getopt(argc,argv,“bens:?”)
(原始代码SEGFULT在
/a.out-n
/a.out
上)

看起来唯一的方法是使用
-ns
或将
-n
放在文件名后面。但是
getopt
的GNULIBC示例非常好-
我重写了一些代码,这样它可以处理所有的标志,但仍然可以正确地处理文件名。它并不完美,但它是:

//在此之前,我删除了for循环。这里不需要它。
//如果使用此代码,请删除for循环。
//此处仅删除了案例“:”
而((opt=getopt(argc,argv,“bens?”)!=-1){
开关(opt){
案例“b”:
bflag++;
打破
案例“e”:
eflag++;
打破
案例“n”:
nflag++;
打破
案例s:
sflag++;
打破
案例“?”:
printf(“用法:cat[-bens][file…]\n”);
出口(1);
}
}
//optind由getopt设置。
//它等于选项后面的直接参数的位置。
//这是因为getopt permutes argv使所有非选项都位于末尾
currentFile=optind;
//没有提供文件名时
如果(currentFile==argc){
printf(“需要文件名!\n”);
返回1;
}
代码的其余部分保持不变。它适用于以下示例:

  • /a.out-sn文件
  • /a.out-ns文件
  • /a.out-s file1 file2
  • /a.out-s file1-n file2
这可能仍然有bug。请尝试一下,如果有什么问题请告诉我

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char **argv) {

    FILE *fp;
    const int bufferSize = 4096;
    char buffer[bufferSize];
    int currentFile = 0;

    for (int i = 1; i < argc; i++) {
        if (argv[i][0] != '-') {
            currentFile = i;
            break;
        }
    }

    int bflag = 0, eflag = 0, nflag = 0, sflag = 0;
    int opt;

    while ((opt = getopt(argc, argv, "bens:?")) != -1) {
        switch(opt) {
          case 'b':
            bflag++;
            break;
          case 'e':
            eflag++;
            break;
          case 'n':
            nflag++;
            break;
          case 's':
             sflag++;
             break;
          case ':':
            printf("option needs a value\n");
            exit(1);
          case '?':
            printf("usage: cat [-bens] [file ...]\n");
            exit(1);
        }
    }
    
    while (currentFile < argc) {
        if (currentFile) {
            fp = fopen(argv[currentFile], "rb");
            if (fp == NULL) {
                fprintf(stderr, "%s: %s: No such file or directory",
                        argv[0], argv[currentFile]);
                exit(1);
            }
        }

        int lineNumber = 1;
        int lastLineBlank = 0;

        while (fgets(buffer, bufferSize, (fp == NULL ? stdin : fp))) {

            int length = strlen(buffer);
            buffer[length - 1] = '\0';

            if (sflag) {
                length = strlen(buffer);
                int currentLineBlank = (length <= 1) ? 1 : 0;
                if (lastLineBlank && currentLineBlank) {
                    continue;
                }
                lastLineBlank = currentLineBlank;
            }

            
            if (bflag) {
                length = strlen(buffer);
                if (length >= 1) {
                    char *tmp = strdup(buffer);
                    buffer[0] = '\0';
                    sprintf(buffer, "%*d\t", 6, lineNumber++);
                    strcat(buffer, tmp);
                }
            } else
            if (nflag) {
                char *tmp = strdup(buffer);
                buffer[0] = '\0';
                sprintf(buffer, "%*d\t", 6, lineNumber++);
                strcat(buffer, tmp);
            }

            if (eflag) {
                length = strlen(buffer);
                buffer[length] = '$';
                buffer[length + 1] = '\0';
            }

            fprintf(stdout, "%s\n", buffer);
        }

        fclose(fp);
        currentFile++;
    }

    return 0;
}