使用 Linux 命令行的人来说,pwd命令是非常有用的,执行 pwd 命令可立刻得知您目前所在的工作目录的绝对路径名称。
认识pwd命令
顾名思义,pwd命令打印当前工作目录或简单的目录用户,目前。 它使用从根 (/) 开始的完整路径打印当前目录名称。 此命令内置于 shell 命令中。
对于内置命令就是shell当做自带的,因为shell当中自己要进行管理,那么就需要一些命令进行管理,不同的shell肯定有不同的shell命令。
我们用type命令就可以看到其的类型,内置shell命令其实就是bash当中内部的命令,就好比我们一个软件内部的嵌套的不同的功能一样;
pwd 的基本语法:
pwd [OPTION]
选项 :
-L (logical) 目录连接链接时,输出连接路径
-P (physical) 输出物理路径
使用默认方式,用 pwd 命令查看默认工作目录的完整路径
使用pwd -P 显示出实际路径
目录连接链接时,pwd显示的是连接路径;pwd -P 显示出实际路径,而非使用连接(link)路径;
POSIX 要求默认值为 -L,但大多数脚本都需要 -P。当前外壳默认为 -L,而独立时
pwd 实现默认为 -P。
最简单的pwd命令实现
实现pwd真的太简单了,只要在程序中使用getcwd()函数就可以实现获得绝对路径的功能了。
#include <stdlib.h>
#include <unistd.h>//getcwd
#include <stdio.h>
int main(int argc, char **argv)
{
char *wd =getcwd(NULL, 0);
if (NULL == wd) {
printf("Get cerrent working directory fail.\n");
exit(-1);
} else {
printf("%s\n", wd);
}
return 0;
}
编译运行:
上面其实已经实现了pwd的功能,但这显然只能实现其功能,而不能了解其工作原理;我们接着往下来!
快速理解inode
在一个文件系统中,一个inode代表一个文件,并使用一个整数值来表示该inode,里面包含了与该文件有关的一些信息。
inode包含很多的文件元信息,但不包含文件名,利用stat命令可以查看一个文件更加详细的inode信息,包括inode编号,占用的块数量,块大小,硬链接个数,atime, mtime, ctime
总之,除了文件名以外的所有文件信息,都存在inode之中。
Linux中的目录
Linux文件系统是目录和文件组成的一种层次结构,目录的起点称为根(root),其名字是一个字符 / 。
在作为路径使用时, 根目录 / 是一个绝对路径,而Linux中也有一些相对路径可用,比如 . 或 ./ 表示当前目录、 … 或 …/ 表示上一级目录、 ~ 或 ~/ 表示当前用户的主目录(家目录)。
在Linux目录中,每个名字有一个inode number,inode number指出了存储数据的硬盘空间的位置。通过ls -i看到名字和inode对应关系。
综上,Linux中,一个文件(包括目录)的文件名,及文件名与inode的对应关系,都是由包含该文件的目录所描述的。
pwd实现
static void file_name_free(struct file_name *p)
{
free (p->buf);
free (p);
}
static struct file_name *file_name_init (void)
{
struct file_name *p = (struct file_name *)malloc (sizeof *p);
/* 从大于 PATH_MAX 的缓冲区开始,但要注意系统
其中 PATH_MAX 非常大——例如,INT_MAX。 */
p->n_alloc = MIN (2 * PATH_MAX, 32 * 1024);
p->buf = (char *)malloc (p->n_alloc);
p->start = p->buf + (p->n_alloc - 1);
p->start[0] = '\0';
return p;
}
/* 将长度为 S_LEN 的名称 S 附加到不断增长的文件名 P 之前。 */
static void file_name_prepend (struct file_name *p, char const *s, size_t s_len)
{
size_t n_free = p->start - p->buf;
if (n_free < 1 + s_len)
{
size_t half = p->n_alloc + 1 + s_len;
char *q = (char *)calloc (2, half);
size_t n_used = p->n_alloc - n_free;
p->start = q + 2 * half - n_used;
memcpy (p->start, p->buf + n_free, n_used);
free (p->buf);
p->buf = q;
p->n_alloc = 2 * half;
}
p->start -= 1 + s_len;
p->start[0] = '/';
memcpy (p->start + 1, s, s_len);
}
/* 返回一个由 N 个 '/' 分隔的“..”组件组成的字符串(malloc'd)。 */
static char *nth_parent(size_t n)
{
char *buf = (char *)calloc(3, n);
char *p = buf;
for (size_t i = 0; i < n; i++)
{
memcpy (p, "../", 3);
p += 3;
}
p[-1] = '\0';
return buf;
}
static inline bool dot_or_dotdot (char const *file_name)
{
if (file_name[0] == '.')
{
char sep = file_name[(file_name[1] == '.') + 1];
return (! sep || ISSLASH (sep));
}
else
return false;
}
/* readdir 的包装器,以便调用者看不到 '.' 的条目。 或“……”。 */
static inline struct dirent const *readdir_ignoring_dot_and_dotdot (DIR *dirp)
{
while (1)
{
struct dirent const *dp = readdir(dirp);
if (dp == NULL || ! dot_or_dotdot(dp->d_name))
return dp;
}
}
static void find_dir_entry (struct stat *dot_sb, struct file_name *file_name,
size_t parent_height)
{
DIR *dirp;
int fd;
struct stat parent_sb;
bool use_lstat;
bool found;
dirp = opendir("..");
if (dirp == NULL)
printf("cannot open directory %s\n",strdup(nth_parent(parent_height)));
fd = dirfd (dirp);
/*chdir()这个系统调用,是改变当前程序的工作目录,不是改变bash的工作目录*/
if ((0 <= fd ? fchdir(fd) : chdir("..")) < 0)
printf("failed to chdir to %s\n",strdup(nth_parent(parent_height)));
if ((0 <= fd ? fstat(fd, &parent_sb) : stat(".", &parent_sb)) < 0)
printf("failed to stat %s\n",strdup(nth_parent(parent_height)));
/*如果父目录和子目录在不同的设备上,那么我们
不能依赖 d_ino 来获取有用的 i-node 编号; 请改用 lstat。 */
use_lstat = (parent_sb.st_dev != dot_sb->st_dev);
found = false;
while (1)
{
struct dirent const *dp;
struct stat ent_sb;
unsigned long long int ino = 0;
errno = 0;
if ((dp = readdir_ignoring_dot_and_dotdot (dirp)) == NULL)
{
if (errno)
{
/* 在 closedir 调用中保存/恢复 errno。 */
int e = errno;
closedir (dirp);
errno = e;
/* 安排在退出此循环后进行诊断。 */
dirp = NULL;
}
break;
}
ino = dp->d_ino;
if (ino == NOT_AN_INODE_NUMBER || use_lstat)
{
if (lstat (dp->d_name, &ent_sb) < 0)
{
/* 跳过我们无法统计的任何条目。 */
continue;
}
ino = ent_sb.st_ino;
}
if (ino != dot_sb->st_ino)
continue;
/* 如果我们不跨越设备边界,那么一个简单的 i-node
匹配就足够了。 */
if ( ! use_lstat || ent_sb.st_dev == dot_sb->st_dev)
{
file_name_prepend(file_name, dp->d_name, strlen(dp->d_name));
found = true;
break;
}
}
if (dirp == NULL || closedir (dirp) != 0)
{
/* N请注意,此诊断适用于 readdir
和关闭失败。 */
printf("reading directory %s\n",strdup(nth_parent(parent_height)));
}
if ( ! found)
printf("couldn't find directory entry in %s with matching i-node",strdup(nth_parent(parent_height)));;
*dot_sb = parent_sb;
}
/* 调用 lstat 以获取“/”的设备和 inode 编号。
失败时,返回NULL。 否则,设置成员
*ROOT_D_I 相应地并返回 ROOT_D_I。 */
struct dev_ino *get_root_dev_ino (struct dev_ino *root_d_i)
{
struct stat statbuf;
if (lstat ("/", &statbuf))
return NULL;
root_d_i->st_ino = statbuf.st_ino;
root_d_i->st_dev = statbuf.st_dev;
return root_d_i;
}
static void robust_getcwd (struct file_name *file_name)
{
size_t height = 1;
struct dev_ino dev_ino_buf;
struct dev_ino *root_dev_ino = get_root_dev_ino (&dev_ino_buf);
struct stat dot_sb;
if (root_dev_ino == NULL)
printf("failed to get attributes of %s\n",strdup("/"));
if (stat (".", &dot_sb) < 0)
printf("failed to stat %s\n",strdup("."));
while (1)
{
find_dir_entry (&dot_sb, file_name, height++);
}
/* 查看是否需要前导斜线; file_name_prepend 添加一个。 */
if (file_name->start[0] == '\0')
file_name_prepend (file_name, "", 0);
}
/* 如果“pwd -L”可接受,则从环境中返回 PWD
输出,否则为 NULL。 */
static char *logical_getcwd (void)
{
struct stat st1;
struct stat st2;
char *wd = getenv("PWD");
char *p;
/* 首先进行文本验证。 */
if (!wd || wd[0] != '/')
return NULL;
p = wd;
while ((p = strstr(p, "/.")))
{
if (!p[2] || p[2] == '/'
|| (p[2] == '.' && (!p[3] || p[3] == '/')))
return NULL;
p++;
}
/* 系统调用验证 */
if (stat(wd, &st1) == 0 && stat (".", &st2) == 0)
return wd;
return NULL;
}
int main(int argc, char **argv)
{
char *wd;
/* POSIX 要求默认值为 -L,但大多数脚本都需要 -P。
当前外壳默认为 -L,而独立时
pwd 实现默认为 -P。 */
bool logical = (getenv ("POSIXLY_CORRECT") != NULL);
while (1)
{
int c = getopt(argc, argv, "LP");
if (c == -1)
break;
switch (c)
{
case 'L':
logical = true;
break;
case 'P':
logical = false;
break;
default:
break;
}
}
if (optind < argc)
printf("ignoring non-option arguments\n");
if(logical)
{
wd = logical_getcwd();
if (wd)
{
puts(wd);
return 0;
}
}
wd = getcwd(NULL, 0);
if (wd != NULL)
{
puts(wd);
free(wd);
}
else
{
struct file_name *file_name = file_name_init();
robust_getcwd(file_name);
puts (file_name->start);
file_name_free(file_name);
}
return 0;
}
编译运行
总结
Linux中用 pwd 命令来查看”当前工作目录“的完整路径。 简单得说,每当你在终端进行操作时,你都会有一个当前工作目录。在不太确定当前位置时,就会使用pwd来判定当前目录在文件系统内的确切位置。
欢迎关注微信公众号【程序猿编码】,欢迎添加本人微信号(17865354792)交流学习。