您的位置:首页 > 运维架构 > Shell

一个简单的“ls -al”实现(其实网上已经有很多了)

2011-01-06 15:44 585 查看

/**
*                      Copyleft (C) 2010  Late Lee
*        This program is tested on LINUX PLATFORM, WITH GCC 4.x.
*        The program is distributed in the hope that it will be
*        useful, but WITHOUT ANY WARRANTY. Please feel free to
*        use the program, and I feel free to ignore the related
*        issues. Any questions or suggestions, or bugs, please
*        contact me at
*        $ echo -n "aHR0cDovL3d3dy5sYXRlbGVlLm9yZwo=" | base64 -d
*        or e-mail to
*        $ echo -n "bGF0ZWxlZUAxNjMuY29tCg==" | base64 -d
*        if you want to do this.
*     
* @file:   myls.c
* @author: Late Lee
* @date:   Thu Jan 6 2011
* @brief:  An "ugly" implementation of "ls -la".
*         
* @test:   gcc -Wall myls.c -o myls
*          "./myls" will display the current directory, or you can specify
*          the directory(or the file), such as "./myls /", etc.
* @note:   I do not know how to print the "real" name of a symbolic link file.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h> /* stat */
#include <grp.h> /* getgrgid() */
#include <pwd.h> /* passwd, getpwuid(), etc */
#include <time.h>
#include <string.h>
#include <dirent.h> /* opendir(), etc */

static int get_file_name(char *file, const char *path)
{
    if (file == NULL || path == NULL)
    {
        printf("Error: do you forget malloc??/n");
        return -1;
    }

    int len = strlen(path);
    int pos = len - 1;

    while (pos>=0 && path[pos]!='/' )
        pos--;

    strcpy(file, path + pos + 1);

    return 0;
}

static int display_file_name(const char *path)
{
    int len = 0;
    char *file = NULL;

    len = strlen(path);
    file = (char *)malloc(len+1);

    get_file_name(file, path);
    printf("%s ", file);
    free(file);
   
    return 0;
}

static int display_attr(const char *file)
{
    struct stat buf;
    int ret;
    char *m;    /* OK here */

    ret = lstat(file, &buf);
    if (ret == -1)
    {
        perror("lstat error");
        //return -1;
        exit(0);
    }
    /**
     * file mode
     * st_mode sample(in oct):
     * 0   12   0  7     4     4
     *     l       rwx   rw-    rw-
     * oct type ?? owner group others
     * see man page for details($man lstat)
     */
    if (S_ISREG(buf.st_mode))
        m = "-";
    else if (S_ISDIR(buf.st_mode))
        m = "d";
    else if (S_ISCHR(buf.st_mode))
        m = "c";
    else if (S_ISBLK(buf.st_mode))
        m = "b";
    else if (S_ISFIFO(buf.st_mode))
        m = "f";
    else if (S_ISLNK(buf.st_mode))
        m = "l";
    else if (S_ISSOCK(buf.st_mode))
        m = "s";
    else    /* just kidding */
        m = "-";
    printf("%s", m);
   
    /*file permission*/
    int n;
    int temp;
    int tmp;
    for (n=8; n>=0; n--)
    {
        /**
         * temp:
         * dec 256  128  64   32   16   8    4    2    1
         * oct 0400 0200 0100 0040 0020 0010 0004 0002 0001
         */
        temp = 1<<n;
        tmp = buf.st_mode & temp;
        if (tmp)
        // if (buf.st_mode & (1<<n))
        {
            switch (n%3)
            {
            case 2: printf("r"); break;
            case 1: printf("w"); break;
            case 0: printf("x"); break;
            }
        }
        else
            printf("-");
    }
    printf(" ");

    /* number of hard link */
    printf("%3d ", buf.st_nlink);

    /* user name */
    struct passwd *pw = getpwuid(buf.st_uid);
    printf("%8s ", pw->pw_name);

    /* group name */
    struct group *grp = getgrgid(buf.st_gid);
    printf("%8s ", grp->gr_name);

    /* file size */
    printf("%5d ", (int)buf.st_size);

    /* last modify time */
    struct tm *t;
    t = localtime(&(buf.st_mtime));
    printf("%4d-%02d-%02d %02d:%02d ", t->tm_year+1900, t->tm_mon+1,
           t->tm_mday, t->tm_hour, t->tm_min);

    /* file name... */
    printf("%s", file);
    return 0;
}
int display(const char *path, int detail)
{
    DIR *dir = NULL;
    struct dirent *de = NULL;
    int ret;
   
    dir = opendir(path);
    if (dir == NULL)
    {
        /**
         * Note: This is not actualy an error!!
         * We show the file, but if it does not exist, we will handle it.
         */
        display_attr(path);
        //display_file_name(path);
        //printf("%s", path);
        printf("/n");
        return 0;
    }
    else
    {
        ret = chdir(path);
        if (ret != 0)
        {
            perror("error change dir");
            return -1;
        }
        while ((de=readdir(dir)) != NULL)
        {
            if (detail)
            {
                display_attr(de->d_name);
                //display_file_name(de->d_name);
                //printf("%s ", de->d_name);
                printf("/n");
            }
            else
                //display_file_name(de->d_name);
                printf("%s ", de->d_name);
        }
    }
    printf("/n");
    closedir(dir);

    return 0;
}
int main(int argc, char *argv[])
{
    if (argc == 1)
        display(".", 1); /* current dir */
    else if (argc == 2)
        display(argv[1], 1); /* the dir you specify */
    else
    {
        printf("Usage: %s [dir|file]/n", argv[0]);
        puts("Display file information of the dir you specify./n");
        exit(0);
    }

    return 0;
}

 

1、实现功能:
类似shell的“ls -al”的输出。默认输出当前目录文件。

可以只简单输出文件名称,需要在程序中的display中第2个参数指定,0为简单输出文件名称。
也可将文件名称作为参数,程序会显示了该文件的相应信息,如果文件无效(不存在),由perror处理。

 

2、未完成:
a、对文件名称不作排序;
b、对main输入参数作简单处理,不涉及复杂的参数处理。
c、格式输出不理想。对于长度不确定的,如用户名或文件大小等等,只大致估计其长度,如用户名为8,文件大小为5,等等。未深入了解shell的ls实现,它的输出格式就很漂亮了,但个人觉得用自己实现起来很麻烦。
d、链接文件的真实文件名称不知道如何处理,暂时未找到资料。

 

3、学习到的:
详细了解了stat结构体的st_mode格式,文件的类型、权限信息均由此成员确定。经gdb调试,如果以八进制输出数据,将有利于理解程序中的处理方法。
如一个可能的例子为
0120744(八进制)
输出效果为lrwxrw-rw-。其中开头的0表示八进制,l表示其为链接文件,rwx分别表示读、写、可执行。八进制后面三们分别表示用户、与用户同组用户、其它用户的权限,以二进制表示,恰好为3位。如无此相应权限,以“-”表示。具体定义请man stat。
注:在处理权限时就使用到了这个技巧。

注意月份格式输出的“%02d”之类的,这样就能输入月份、日期前面的“0”了。 

 

另外,发现学习Linux的命令时,最好在纸上作笔记,因为这样才是我们真正需要的命令。比看网上的教程高效多了。

 

补:其实这个程序有一些多余的代码,因为在opendir返回的de中已经得到了文件名了,存放de->d_name中,所以可以不在再在这个“路径”中查找文件名称了,直接指定它,或者直接输出它就可以了。现将程序作小小改动。过了一天才发现这个问题,惭愧啊!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  file path struct null shell linux
相关文章推荐