pwd指令的简单实现

  • pwd命令作用

Linux中用** pwd **命令来查看”当前工作目录“的完整路径。 简单得说,每当你在终端进行操作时,你都会有一个当前工作目录。
在不太确定当前位置时,就会使用pwd来判定当前目录在文件系统内的确切位置。

1.命令格式:
pwd [选项]

2.命令功能:
查看”当前工作目录“的完整路径

3.常用参数:
一般情况下不带任何参数
如果目录是链接时:
格式:pwd -P 显示出实际路径,而非使用连接(link)路径。

首先通过man pwd查看pwd的详细用法,如下图:

知道了函数getcwd可能对于pwd命令的实现有所帮助,之后通过命令man getcwd查看此函数的具体用法
如下图:

知道了可以通过此函数来简单实现pwd命令。
可以采取令 buf 为 NULL并使 size 为零(百度百科里介绍可以使用负值但我测试的时候是段错误)来使 getcwd 调用 malloc 动态给 buf 分配,但是这种情况要特别注意使用后释放缓冲以防止内存泄漏。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(void)
{
    char *path = NULL;
    path = getcwd(NULL,0);
    puts(path);
    free(path);
    return 0;
}
  • 通过命令man -k status|grep 2查找可用函数,如下图所示

老师在课堂给出提示使用stat函数

  • 1.stat函数讲解
stat函数讲解

表头文件:    #include <sys/stat.h>
             #include <unistd.h>
定义函数:    int stat(const char *file_name, struct stat *buf);
函数说明:    通过文件名filename获取文件信息,并保存在buf所指的结构体stat中
返回值:      执行成功则返回0,失败返回-1,错误代码存于errno
  • 2 文件对应的属性
    通过man 2 stat查看函数stat
    image
    通过上面提供的函数,返回一个结构体,保存着文件的信息。

这一个结构体的成员表示,文件的索引信息(进入点),“number”告诉我们它是一个数字表示,而不是一个确切的路径,这就好比我们有时候用文件描述符来操作文件,而不用字符数组(文件名)来操作。
也就是说,我们想要找到文件的路径,st_ino这个信息试关键。

具体思路:

计算机内核为每一个目录都设置了一个指向自己的i节点入口,即".",还有一个指向其父目录i节点的入口,即”..",我们可以使用cd . 或者cd .. 来回到当前目录下或者父目录下。我们首先获取当前目录的i节点编号,但是并不能知道当前目录的名称,我们切换到其的父目录,在里面寻找当前i节点编号对应的文件名即可。这样我们就很容易联想到使用递归来实现,但是终止条件是什么呢?在Unix文件系统的根目录中,“."和“..”指向同一个i节点,我们可以以此判断是否发到达了根目录。如下图所示:

伪代码如下:

while(“."和“..”不指向同一个i节点)
切换到当前的父目录,在里面寻找当前i节点编号对应的文件名
收集

最后打印字符数组
  • get_inode函数--使用stat函数来得到当前目录下的文件信息,主要是获得i-node信息。
ino_t get_inode(char *dirname)  
{  
    struct stat a;  
    if (stat(dirname, &info) == -1)  
    {  
        perror("dirname");  
        exit(1);  
    }  
  
    return a.st_ino;  
}  
  • 要读取路径,必定要先打开路径,路径如何打开可以用指令查询一下:man -k dir | grep open 得到函数opendir
    如下图

输入指令:man 3 opendir查看详细信息

输入参数为一个文件(目录)名,才能打开该目录,并且返回为DIR类型

我们已经知道目录名,当前目录的目录名为.,父级目录的目录名为..。

  • 如何将它的各个父目录读取出来呢?跟读取有关(read)
    用指令搜索查询一下:man -k dir | grep read
    如下图:

找到相关项后输入指令:man readdir

其中有d_ino和d_name[256],这两者应该是一一对应的,也就是说我只要取得了其索引号,就可以将其翻译为文件名了。

使用函数void inode_to_dirname(ino_t inode_num, char buf,int buflen) 来获得当前文件名,并添加到buf中

void inode_to_dirname(ino_t inode_num, char *buf,int buflen)  
{  
    DIR *dir_ptr;  
    struct dirent *dire;  
    if ((dir_ptr = opendir(".")) == NULL)  
    {  
        perror(".");  
        exit(1);  
    }  
  
    while ((dire = readdir(dir_ptr)) != NULL)  
    {  
        if (dire->d_ino == inode_num)  
        {  
            strncpy(buf, dire->d_name, buflen);  
            buf[strlen(buf)] = '\0';  
            closedir(dir_ptr);  
            return ;  
        }  
    }  
    fprintf(stderr, "error looking for inode number %d\n", (int)inode_num);  
    exit(1);  
}  

此函数是将索引节点转化为相应的文件名的过程,具体方法是将一个个读取的目录的ino信息与传参进来的ino信息做比对,如果相同,则说明找到了正确目录,把文件名拷贝到字符数组就行;如果比对结果不相同,则继续读取下一个目录。

void get_work_dir(ino_t inode_num)  
{  
    ino_t parent_inode;  
    char buf[SIZE];  
    if (get_inode("..") != inode_num)  
    {  
        chdir("..");  
        inode_to_dirname(inode_num, buf, SIZE);  
        parent_inode = get_inode(".");  
        get_work_dir(parent_inode);  
        printf("/%s", buf);  
    }  
}  

此函数实现了递归调用,具体实现内容如下:

传入一个索引节点,并求得父目录的索引节点,判断两者是否相等,相等则说明已经到了根文件夹下,可以终止递归调用
如若不相等,则进入父目录,然后通过inum_to_name函数功能,将之前的目录名拷贝到its_name字符数组中,准备输出打印

具体代码

实现效果如下图