5.1 快速导航

在命令行下,你如何穿越文件系统的“丛林”而不致迷路?你又如何快速定位所需的文件和目录?如果你仅仅了解导航的基本用法,那么恐怕是不够的。在本节,我将教你几个必备的技能,使你能够轻车熟路的驾驭命令行导航。

5.1.1 回到用户主目录

也许你已经知道 ~ (波浪线) 这个特殊字符代表用户的主目录,若是想要回到自己的主目录,那么我们可以执行:

xiaodong@codeland:~$ cd ~

但是且慢,我想在此告诉你的是,不带任何参数的 cd 命令同样能够将你带回主目录:

xiaodong@codeland:~$ cd

换句话说,这两个命令行所达到的效果是相同的。然而,两相比较起来,后者比前者可以少输两个字符,和乐而不为呢?

说到 ~ (波浪线),你还应该了解的一个技巧是,我们可以利用它来转到别的用户的主目录。例如:

xiaodong@codeland:~$ cd ~mingji

我们在 ~ (波浪线) 后面直接跟上 mingji 这个用户名,于是 cd 将我们带到了该用户的主目录。值得注意的是,以下命令行与它并不相同:

xiaodong@codeland:~$ cd ~/mingji

请注意 ~ (波浪线) 后的 / (斜杠),这行命令的作用是转到当前用户主目录下的子目录 mingji

5.1.2 回到上次工作的目录

我经常使用的一个导航场景是,在目录 A 中处理了任务之后,接着转到目录 B 中处理任务,一旦完成,我需要再次回到目录 A 继续工作。此时,我们可以执行下面的命令来回到上次工作的目录:

xiaodong@codeland:~$ cd ~/prj/usingcli
xiaodong@codeland:~/prj/usingcli$ pwd
/home/xiaodong/prj/usingcli
xiaodong@codeland:~/prj/usingcli$ cd ~/cli
xiaodong@codeland:~/cli$ pwd
/home/xiaodong/cli
xiaodong@codeland:~/cli$ cd -
/home/xiaodong/prj/usingcli
xiaodong@codeland:~/prj/usingcli$ pwd
/home/xiaodong/prj/usingcli

在此,我第一次工作的目录是 ~/prj/usingcli,第二次工作的目录是 ~/cli。通过执行 cd 后跟一个 - (减号),我们快速的回到了第一次工作的目录。cd - 命令相当于执行 cd "$OLDPWD"pwd 两条命令。

xiaodong@codeland:~$ cd "$OLDPWD" && pwd

我们还可以继续重复执行 cd -,这样就会在 ~/prj/usingcli~/cli 两个目录之间反复切换。

5.1.3 访问常用目录

对于需要频繁访问的深层次目录,直接导航起来感觉还是比较麻烦。幸运的是,bash 和 zsh 两个都为我们提供了 $CDPATH 变量。这是一个与 $PATH 类似的变量,它由 : (冒号) 分隔的路径列表组成。利用 $CDPATH,我们能够将常用的目录保存起来,以便 cd 为我们直接转到这些目录。比如:

xiaodong@codeland:~$ CDPATH=:~:~/src:~/prj/usingcli

在这里,我们将 ~ (用户主目录)、~/src、以及 ~/prj/usingcli 等目录加到了 $CDPATH 中。注意 = (等号) 后面 : (冒号) 的左边为空,它表示当前目录,你应当予以保留。否则,在相对路径的情况下 ,cd 就不能转到当前目录下的子目录了。

现在,假如我们打算转到 ~/prj/usingcli/build 目录下的话,那么只要执行下列命令即可:

xiaodong@codeland:~$ cd build
xiaodong@codeland:~/prj/usingcli/build$

这个例子同时也告诉我们,加到 $CDPATH 路径列表的目录为待导航的目标目录的父目录。

除了 $CDPATH 变量,zsh 也支持 $cdpath 变量。

5.1.4 自动纠正错误

在用 cd 导航目录时,我们免不了偶尔会输错目录的名称。bash 有一个名为 cdspell 的选项可以帮助我们自动纠正拼写错误,并导航到正确的目录。像是不正确的字母顺序、缺少或者多余的字符等错误,cdspell 都能纠正。

我们在享用如此好的功能之前,需要首先开启 bash 的控制选项:

xiaodong@codeland:~$ shopt -s cdspell

shopt 命令的 -s 用于启用 cdspell 选项。

现在我们来试一下 cdspell 的效果,我们原本是想要导航到 /etc 目录,但是我们却错输成了 /ect。不过没有关系,bash 已经帮我们自动纠正了错误,并且转到了正确的目录。

xiaodong@codeland:~$ cd /ect
/etc
xiaodong@codeland:/etc$ cd -
xiaodong@codeland:~$ cd /et
/etc
xiaodong@codeland:/etc$ cd -
xiaodong@codeland:~$ cd /etcd
/etc
xiaodong@codeland:/etc$

在 zsh 中,我们可以给 cd 命令两个参数,它们分别是搜索与替换字符串。zsh 将根据搜索字符串来查看当前工作目录,然后使用第二个字符串替换它,并转到替换后的目录。

xiaodong@codeland:~/cli/1.15.8/src$ pwd
/home/xiaodong/cli/1.15.8/src
xiaodong@codeland:~/cli/1.15.8/src$ cd 1.15.8 1.15.9
xiaodong@codeland:~/cli/1.15.9/src$ pwd
/home/xiaodong/cli/1.15.9/src

本例中,我们的当前工作目录为 /home/xiaodong/cli/1.15.8/srccd 命令的第一个参数 1.15.8 跟当前工作目录相匹配。zsh 用 1.15.9 替换了 1.15.8,然后转到了新的目录 /home/xiaodong/cli/1.15.9/src

5.1.5 自动导航

因为 cd 命令是如此常用,我们使用它的频率又那么高,所以 bash 和 zsh 两个都为 cd 命令提供了一个捷径,对像我一样的“懒人”来说,autocd 选项极其有用。

在 bash 中,我们可以通过下面的命令来启用 autocd 选项:

xiaodong@codeland:~$ shopt -s autocd

与此对应的 zsh 指令为:

xiaodong@codeland:~$ setopt autocd

现在假设我们想导航到 ~/prj 目录,代替执行:

xiaodong@codeland:~$ cd prj

我们可以省略 cd 命令,直接执行:

xiaodong@codeland:~$ prj
xiaodong@codeland:~/prj$ pwd
/home/xiaodong/prj

5.1.6 使用目录栈

前面我们讲到的 cd - 允许我们在两个目录之间进行切换,如果我们想要在更多个目录之间切换,那么它就无能为力了。不过,为了帮助我们解决这个问题,bash 和 zsh 提供了目录栈功能。

两个最基本的目录栈命令是 pushdpopd。其中,pushd 命令将一个目录添加到目录栈中,而 popd 命令则从目录栈中移除上次添加的目录。

xiaodong@codeland:~$ pwd
/home/xiaodong
xiaodong@codeland:~$ pushd ~/cli
~/cli ~
xiaodong@codeland:~/cli$ pushd ~/prj
~/prj ~/cli ~
xiaodong@codeland:~/prj$ popd
~/cli ~
xiaodong@codeland:~/cli$ popd
~
xiaodong@codeland:~$

在这个例子中,我们第一次执行 pushd ~/cli 后,将 ~/cli 添加到目录栈的同时,并且转到了该目录。接着,我们继续执行 pushd ~/prj,又将 ~/prj 目录添加到了目录栈。此刻,我们位于 ~/prj 目录,目录栈中包括 3 个条目:

~/prj ~/cli ~

出栈的顺序跟入栈的顺序相反,第一次执行 popd 命令后,移除了目录栈中的最左边的条目 ~/prj,并转到了相邻的 ~/cli 目录。再次执行 popd 命令,则又移除 ~/cli 条目,然后转到 ~ 目录。

如果你在执行多次入栈与出栈后忘了目录栈中还有哪些条目的话,那么可以执行 dirs -v 命令来查看:

xiaodong@codeland:~$ dirs -v
 0  ~/prj
 1  ~/cli
 2  ~

dirs -v 为我们列出了目录栈中的所有条目,每行一条,而且开头具有编号,以便我们引用。例如:

xiaodong@codeland:~/prj$ pushd +1
~/cli ~ ~/prj
xiaodong@codeland:~/cli$

执行 pushd +1 将使 ~/cli 成为目录栈的顶端,并变成当前工作目录。我们可以通过再次执行 dirs -v 命令来确认这一点:

xiaodong@codeland:~/cli$ dirs -v
 0  ~/cli
 1  ~
 2  ~/prj
xiaodong@codeland:~/cli$ pwd
/home/xiaodong/cli

pushd 命令中的 + (加号) 用于从上往下计数。我们也可以使用 - (减号) 来从下往上计数。比如:

xiaodong@codeland:~/cli$ popd -1
~/cli ~/prj
xiaodong@codeland:~/cli$ dirs -v
 0  ~/cli
 1  ~/prj

执行 popd -1 命令后从目录栈中移除了倒数第二个条目 ~