CuSO4_Deposit's Electrolytic Infodump

Manipulating Directories - Shell Builtins cd pushd and popd

大多数现代 shell 有一系列 shell builtins(例:zsh ),其中一些可以用来操作目录。

为了操作目录,在内存中维护了一个目录栈结构。在 bash 中也可以通过 $DIRSTACK shell variable 访问到。bash 的目录栈介绍页zsh 的目录栈介绍页

通过 pushd 和 popd,可以进入一系列目录并且按反序退出。

[1:cuso4d@nightcord-laborari:~]
$ pwd
/home/cuso4d
[1:cuso4d@nightcord-laborari:~]
$ pushd ~/source/zsh
~/source/zsh ~
[1:cuso4d@nightcord-laborari:~/source/zsh on master]
$ pushd ~/.ssh
~/.ssh ~/source/zsh ~
[1:cuso4d@nightcord-laborari:~/.ssh]
$ popd
~/source/zsh ~
[1:cuso4d@nightcord-laborari:~/source/zsh on master]
$ popd
~
[1:cuso4d@nightcord-laborari:~]
$ pwd
/home/cuso4d

以 zsh 为例子,目录栈是使用链表实现的。位置在 Src/Bulitin.c

static struct builtin builtins[] =
{
	// ...
	BUILTIN("cd", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 2, BIN_CD, "qsPL", NULL),
    BUILTIN("popd", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 1, BIN_POPD, "q", NULL),
    BUILTIN("pushd", BINF_SKIPINVALID | BINF_SKIPDASH | BINF_DASHDASHVALID, bin_cd, 0, 2, BIN_PUSHD, "qsPL", NULL),
    // ...
}    
/* Builtin option handling */
#define BINF_SKIPINVALID	(1<<12)	/* Treat invalid option as argument */
#define BINF_KEEPNUM		(1<<13) /* `[-+]NUM' can be an option */
#define BINF_SKIPDASH		(1<<14) /* Treat `-' as argument (maybe `+') */
#define BINF_DASHDASHVALID	(1<<15) /* Handle `--' even if SKIPINVALD */

bin_cd 的实现

/* set if we are resolving links to their true paths */
static int chasinglinks;

/* The main pwd changing function.  The real work is done by other     *
 * functions.  cd_get_dest() does the initial argument processing;     *
 * cd_do_chdir() actually changes directory, if possible; cd_new_pwd() *
 * does the ancillary processing associated with actually changing    *
 * directory.                                                          */

/**/
int
bin_cd(char *nam, char **argv, Options ops, int func)
{
    LinkNode dir;

    if (isset(RESTRICTED)) {
	zwarnnam(nam, "restricted");
	return 1;
    }
    doprintdir = (doprintdir == -1);

    chasinglinks = OPT_ISSET(ops,'P') ||
	(isset(CHASELINKS) && !OPT_ISSET(ops,'L'));
    queue_signals();
    zpushnode(dirstack, ztrdup(pwd));
    if (!(dir = cd_get_dest(nam, argv, OPT_ISSET(ops,'s'), func))) {
	zsfree(getlinknode(dirstack));
	unqueue_signals();
	return 1;
    }
    cd_new_pwd(func, dir, OPT_ISSET(ops, 'q'));

    unqueue_signals();
    return 0;
}

#Shell