2021-2022-1-diocs-Linux系统编程-sort

20191218 2021-2022-1-diocs-Linux系统编程-sort

一、任务详情

  1. 用man sort 查看sort的帮助文档
  2. sort常用选项有哪些,都有什么功能?提交相关使用的截图
  3. 如果让你编写sort,你怎么实现?写出伪代码和相关的函数或系统调用

二、实践过程

sort帮助文档

在OpenEuler环境下使用man -k sort,发现并没有找到想要的sort

直接用man sortman 2 sort也是没有找到
于是我使用比较万能的sort --help命令来查看sort的帮助文档


总结sort用法如下

  • sort格式
    sort [-bcdfimMnr][-o<输出文件>][-t<分隔字符>][+<起始栏位>-<结束栏位>][--help][--verison][文件][-k field1[,field2]]
  • sort常用选项
    -b 忽略每行前面开始出的空格字符。
    -c 检查文件是否已经按照顺序排序。
    -d 排序时,处理英文字母、数字及空格字符外,忽略其他的字符。
    -f 排序时,将小写字母视为大写字母。
    -i 排序时,除了040至176之间的ASCII字符外,忽略其他的字符。
    -m 将几个排序好的文件进行合并。
    -M 将前面3个字母依照月份的缩写进行排序。
    -n 依照数值的大小排序。
    -u 意味着是唯一的(unique),输出的结果是去完重了的。
    -o<输出文件> 将排序后的结果存入指定的文件。
    -r 以相反的顺序来排序。
    -t<分隔字符> 指定排序时所用的栏位分隔字符。
    +<起始栏位>-<结束栏位> 以指定的栏位来排序,范围由起始栏位到结束栏位的前一栏位。
    --help 显示帮助。
    --version 显示版本信息。
    [-k field1[,field2]] 按指定的列进行排序。

     补充说明:sort可针对文本文件的内容,以行为单位来排序。       

sort实践

** sort的工作原理**
sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出。

-b
忽略前空白进行排序(这里的空白是指从第一个可见字符开始比较,不仅仅是忽略前导空格)

-o
指定输出文件
sort默认是把结果输出到标准输出,所以需要用重定向才能将结果写入文件,形如sort filename > newfile。
但是,如果你想把排序结果输出到原文件中,用重定向就需要使用追加的方式,经过尝试,我发现这样追加只会把原文件直接清空

如果加上-o进行指定文件输出则可以解决这个问题

-c
检查文件是否已排好序,若排好序不进行输出,若未排好序则进行输出。

对刚刚的文件进行检验发现文件内容并没有发生改变,查找资料后知道需要加-o参数指定排序好的内容的输出文件。

-n
按照数值大小排序(若不指定将默认以 ASCII 码的次序排列,并将结果输出到标准输出)

-f
将小写字母视为大写字母

-u
去除重复元素

可以发现加上-b参数后“ 2333”和“2333”也只保留了第一个

-d
经按照英文字母、数字及空格字符排序

-r
倒序排序(sort默认的排序方式为升序排列)

-t

stu.txt文件中每一列以空格隔开,第一列是学号,第二列是姓名,第三列是寝室号,第四列是体育爱好
可是直接在-t多打一个空格sort命令并不能识别

只需要用引号(双引号、单引号都可以)将空格括起来即可解决

注意此时是按照第一列的内容排序的

-k
在不加该参数时,sort默任按照第一列文件内容排序,如果需要指定则需要通过-k 列数实现

注意这里的列数是从1开始的

-m
将多个排好序的文件合并

sort实现思路

首先,对sort中常用参数做一个分类,发现只有-o参数和-c不能同时存在,其余基本上都可以组合使用。
用正则表达式实现命令行中可以在任意位置输入参数,
其中还要注意sort中的一些默认值:-k参数缺省时默认按照第一列对文件进行排列,-t缺省时默认' '分隔,-n缺省时默认按字典顺序升序排列……
思路比较清晰一点、比较好实现的参数像
-b,在读取字符串或者文件时如果遇到不可见字符就跳过即可;
-n,用stdlib库中的atoi、atol把字符串转成整数或者atof把字符串转换成双精度浮点数,再进行排序即可;
-f,将所有读到的字符全部转换成大写字母即可(一个islower判断是否为小写,如果是则转成大写即+32);
-r,将排序条件改成大的在前即可;
-u,先把文件中所有内容按行读进来(或者从键盘一行一行读入),两层循环遍历一遍所有内容,每次循环用strcmp函数查重,如果相同则去掉后一个(将其置为NULL或''),之后再进行排序;
-h/H 、--help,输出各参数及其用法、格式说明,退出;
-t,在读取该参数后紧接着再读入一个字符(可以用单引号括起来)作为每列的分隔符;
-k,在读取该参数后紧接着再读入一个整数,表示要依据第几列进行排序……
以上所有排序都可以使用C语言自带的qsort函数void qsort(void* base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*));实现,其中最后一个参数为自定义的cmp函数(排序规则),返回一个整型的数。
其中的难点包括文件操作、参数的读取(要考虑到用户输入参数位置比较随意的特点)
我在网上找到了一份代码,结合自己的理解,最后实现了-t、-n、-r、f、-h、-k几个参数(实现的-k参数后接的是指定列数-1),并可以叠加运行,处理的对象是一个文件中的内容。
这里展示部分代码的关键部分,完整代码已上传至我的码云仓库:第四周实践代码
mysort.c

static void sort_usage_exit(int status)
{
    if(status != 0)
    {
        fprintf(stderr, "Try '%s --help' for more infomation
",
                program_name);
    }
    else
    {
        printf("Usage: %s   [OPTION] FILE
", program_name);
        printf("-n              Sort by number instead of string
");
        printf("-r              Reverse sort
");
        printf("-t,             Separator, default is '\t'
");
        printf("-k,             Sort by which sector, default is 0
");
        printf("-f,             Ignore case
");
        printf("-h(-H)  --help  Show help information
");
    }

    exit(status);
}

static void init_data()
{
    memset(&g_filedata, 0, sizeof(g_filedata));
}

static void init_option(struct sort_option *op)
{
    op->n = 0;
    op->r = 0;
    op->t = '	';
    op->k = 0;
    op->f = 0;
}

static void fill_t(struct sort_option *op, const char *str)
{
    if(strlen(str) > 1)
    {
        fprintf(stderr,
                "[%s]is error, only set one charactor
",
                str);
        exit(1);
    }
    op->t = str[0];
}

static void fill_k(struct sort_option *op, char *str)
{
    if(!is_digit(str, strlen(str)))
    {
        fprintf(stderr,
                "[%s] is not a number
",
                str);
        exit(1);
    }

    op->k = atoi(str);
}

static size_t get_simfile_size(const char *file)
{
    struct stat         stabuf;

    if(stat(file, &stabuf) != 0)
    {
        fprintf(stderr,
                "stat [%s] error[%s]
",
                file, strerror(errno));
        exit(1);
    }

    if(!S_ISREG(stabuf.st_mode))
    {
        fprintf(stderr,
                "file [%s] is not a simple file
",
                file);
        exit(1);
    }

    return stabuf.st_size;
}

static int fill_line(const char *token)
{
    size_t              index = g_filedata.used;

    if(index == MAX_LINE_NUM)
        return 1;

    g_filedata.dataarr[index].base = (char *)token;
    g_filedata.dataarr[index].size = strlen(token);
    g_filedata.dataarr[index].line_no = g_filedata.used++;

    return 0;
}

static int fill_data(char *pdata)
{
    const char          *sep = "
";
    char                *token;

    init_data();
    token = strtok(pdata, sep);
    while(token != NULL)
    {
        if(fill_line(token))
            break;
        token = strtok(NULL, sep);
    }

    return 0;
}

static void pr_sorteddata()
{
    int             i;

    for(i = 0; i < g_filedata.used; ++i)
    {
        if(write(STDOUT_FILENO, g_filedata.dataarr[i].base, g_filedata.dataarr[i].size) != g_filedata.dataarr[i].size)
            perror("write");
        if(write(STDOUT_FILENO, "
", 1) != 1)
            perror("write2");
    }

}

static void get_field(char *buf)
{
    char            sep[2];
    char            *token;
    int             field_num = (int)g_op.k;

    sprintf(sep, "%c", g_op.t);

    token = strtok(buf, sep);
    while(token != NULL && field_num-- > 0)
    {
        token = strtok(NULL, sep);
    }
    
    if(token){
        memmove(buf, token, strlen(token)); 
        buf[strlen(token)] = 0;
    }
    else
        buf[0] = 0;
}

static int cmp_str(const void *arg1, const void *arg2)
{
    int         rc;
    char        buf1[MAX_LINE_BUF_SIZE+1], buf2[MAX_LINE_BUF_SIZE+1];

    memset(buf1, 0, sizeof(buf1));
    memset(buf2, 0, sizeof(buf2));

    snprintf(buf1, MAX_LINE_BUF_SIZE, "%s", *(char **)arg1);
    snprintf(buf2, MAX_LINE_BUF_SIZE, "%s", *(char **)arg2);

    /*更新buf1, buf2中内容为需要比较的列 */
    get_field(buf1);
    get_field(buf2);

    if(g_op.n &&
       is_digit(buf1, strlen(buf1)) &&
       is_digit(buf2, strlen(buf2)))
        rc = atoi(buf1)-atoi(buf2);
    else if(g_op.f)
        rc = strcasecmp(buf1, buf2);
    else
        rc = strcmp(buf1, buf2);

    return g_op.r ? -rc : rc;
}

static void sort_data()
{
    qsort(g_filedata.dataarr, g_filedata.used, sizeof(struct one_line), cmp_str);
}

static int sort(const char*file)
{
    size_t  filesize = get_simfile_size(file);
    char    *pmapfile = NULL;
    int     fd = -1, err = 0;

    if((fd = open(file, O_RDONLY)) < 0)
    {
        perror("open");
        exit(1);
    }

    if((pmapfile = (char *)mmap(0, filesize, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
    {
        perror("mmap");
        exit(1);
    }
    if((err = fill_data(pmapfile)) != 0)
        goto end;

    sort_data();
    pr_sorteddata();

end:
    if(pmapfile != NULL)
        munmap(pmapfile, filesize);
    if(fd != -1)
        close(fd);

    return err;
}

在OpenEuler下实践

  • -t和-k参数

  • -r参数

  • -h参数

  • -n参数

  • -f参数

原文地址:https://www.cnblogs.com/20191218tangqiheng/p/15342457.html