5 /shell(Linux)

5.1 shell 的类型

登录系统时,系统启动什么样的 shell 程序取决于你的个人用户配置。

在/etc/passwd 文件中,用户记录的第 7 个字段中列出了该用户的默认 shell 程序。只要用户登录某个虚拟控制台终端或是在 GUI 中启动终端仿真器,默认的 shell 程序就会启动。

在下面的例子中,用户 christine 使用 GNU bash shell 作为自己的默认 shell 程序:

$ cat /etc/passwd
[...]
christine:x:1001:1001::/home/christine:/bin/bash
$
bash shell

在现代 Linux 系统中,bash shell 程序(bash)通常位于/usr/bin 目录。也有可能位于/bin 目录。which bash 命令可以帮助找出 bash shell 的位置:

$ which bash
/usr/bin/bash
$

长列表中文件名尾部的星号(*)表明 bash 文件(bash shell)是一个可执行程序。

$ ls -lF /usr/bin/bash
-rwxr-xr-x. 1 root root 1219248 Nov 8 11:30 /usr/bin/bash*
$

注意 在现代 Linux 系统中,/bin 目录通常是/usr/bin/目录的符号链接,这就是为什么用户christine 的默认 shell 程序是/bin/bash,但 bash shell 程序实际位于/usr/bin/目录。涉及到有关符号链接(软链接)的相关内容。

tcsh

该 Linux 系统中还存在其他的 shell 程序,其中就有 tcsh,其源自最初的 C shell:

$ which tcsh
/usr/bin/tcsh
$ ls -lF /usr/bin/tcsh
-rwxr-xr-x. 1 root root 465200 May 14 2019 /usr/bin/tcsh*
$
zsh

这是 bash shell 另一个更复杂的版本,兼具了 tcsh 的一些特性和其他元素。

$ which zsh
/usr/bin/zsh
$ ls -lF /usr/bin/zsh
-rwxr-xr-x. 1 root root 879872 May 11 2019 /usr/bin/zsh*
$

提示 如果你在自己的 Linux 系统中没有找到这些 shell,可以自行安装,具体方法第 9 章。

C shell

C shell是指向 tcsh shell 的软链接(参见第 3 章):

$ which csh
/usr/bin/csh
$ ls -lF /usr/bin/csh
lrwxrwxrwx. 1 root root 4 May 14 2019 /usr/bin/csh -> tcsh*
$

在基于 Debian 的 Linux 系统(比如 Ubuntu)中经常会碰到 dash,这是 Ash shell 的另一个
版本。

$ which dash
/usr/bin/dash
$ ls -lF /usr/bin/dash
-rwxr-xr-x 1 root root 129816 Jul 18 2019 /usr/bin/dash*
$

在大多数 Linux 系统中,/etc/shells 文件中列出了各种已安装的 shell,这些 shell 可以作为用
户的默认 shell。

$ cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/csh
/bin/tcsh
/usr/bin/csh
/usr/bin/tcsh
/usr/bin/zsh
/bin/zsh
$

在很多 Linux 发行版中, shell 文件似乎存在于两个位置:/bin 和/usr/bin。/bin 是指向/usr/bin 的符号链接。

由于 bash shell 的广为流行,作为默认的交互式 shell(default interactive shell)也称登录 shell(login shell),只要用户登录某个虚拟控制台终端或是在 GUI 中启动终端仿真器,该 shell 就会启动。
作为默认的系统 shell(default system shell),sh(/bin/sh)用于那些需要在启动时使用的系
统 shell 脚本。
你经常会看到某些发行版使用软链接将默认的系统 shell 指向 bash shell,比如 CentOS 发行版:

$ which sh
/usr/bin/sh
$ ls -l /usr/bin/sh
lrwxrwxrwx. 1 root root 4 Nov 8 11:30 /usr/bin/sh -> bash
$

但要注意,在有些发行版中,默认的系统 shell 并不指向 bash shell,比如 Ubuntu 发行版:

$ which sh
/usr/bin/sh
$ ls -l /usr/bin/sh
lrwxrwxrwx 1 root root 4 Mar 10 18:43 /usr/bin/sh -> dash
$

在这里,默认的系统是 dash shell。
提示 对 bash shell 脚本来说,这两种 shell(默认的交互 shell 和默认的系统 shell)可能会导致
问题。一定要阅读第 11 章中有关 bash shell 脚本首行的语法要求,以避免这些麻烦。

并不是非得使用默认的交互式 shell。可以启动任意一种已安装的 shell,只需输入其名称即可。但屏幕上不会有任何提示或消息表明你当前使用的是哪种 shell。$0 变量可以助你

命令 echo $0

会显示当前 shell 的名称,提供必要的参考。
注意 使用 echo $0 显示当前所用 shell 的做法仅限在 shell 命令行中使用。如果在 shell 脚本中
使用,则显示的是该脚本的名称。如需了解详情,请参见第 14 章。
输入命令 dash,启动 dash shell,通过echo $0 显示新的 shell。

$ echo $0
-bash
$
$ dash
$
$ echo $0
dash
$

注意 在上面的例子中,注意第一个 echo $0 命令的输出:bash 之前有一个连字符(-)。这
表明该 shell 是用户的登录 shell
$是 dash shell 的 CLI 提示符。输入命令 exit 就可以退出 dash shell 程序(对于 bash shell 也
是如此):
$ echo $0
dash
$ exit
$ echo $0
-bash
$
虽然在各种 shell 之间来回切换看起来并不难,但幕后发生的事情可没那么简单。为了理解
这个过程,下一节将探究登录 shell新启动的 shell 之间的关系。

5.2 shell 的父子关系

用户登录时所启动的默认的交互式 shell(登录 shell)是一个父 shell。到目前为止,都是由父 shell 提供 CLI 提示符并等待命令输入。
当你在 CLI 提示符处输入 bash 命令(或是其他 shell 程序名)时,会创建新的 shell 程序。
这是一个子 shell。子 shell 也拥有 CLI 提示符,同样会等待命令输入。
在输入 bash 并生成子 shell 时,屏幕上不会显示任何相关信息,要想搞清楚来龙去脉,需
要用到第 4 章中讲过的 ps 命令。在生成子 shell 的前后配合-f 选项来使用:

$ ps -f
UID PID PPID C STIME TTY TIME CMD
christi+ 6160 6156 0 11:01 pts/1 00:00:00 -bash
christi+ 7141 6160 0 12:51 pts/1 00:00:00 ps -f
$
$ bash
$
$ ps -f
UID PID PPID C STIME TTY TIME CMD
christi+ 6160 6156 0 11:01 pts/1 00:00:00 -bash
christi+ 7142 6160 0 12:52 pts/1 00:00:00 bash
christi+ 7164 7142 0 12:52 pts/1 00:00:00 ps -f
$

进程就是正在运行的程序。bash shell 是一个程序,当它运行的时候,就成了进程。一个运行着的 shell 同样是进程。因此,在说到运行 bash shell 的时候,经常会看到“shell”和“进程”这两个词交换使用。

输入命令 bash 之后,就创建了一个子 shell。第二个 ps -f 是在子 shell 中执行的。有两个 bash shell 程序在运行。一个是父 shell 进程,其 PID 为 6160。另一个是子 shell 进程,其 PID 为 7142。注意,子 shell 的父进程 ID(PPID)是 6160,表明这个进程就是该子 shell 的父进程。图                                

在生成子 shell 进程时,只有部分父进程的环境被复制到了子 shell 环境中。这会对包括变量在内的一些东西造成影响 

子 shell 既可以从父 shell 中创建,也可以从另一个子 shell 中创建:

$ ps -f
UID PID PPID C STIME TTY TIME CMD
christi+ 7650 7649 0 16:01 pts/0 00:00:00 -bash
christi+ 7686 7650 0 16:02 pts/0 00:00:00 ps -f
$
$ bash
$ bash
$ bash
$
$ ps --forest
PID TTY TIME CMD
7650 pts/0 00:00:00 bash
7687 pts/0 00:00:00 \_ bash
7709 pts/0 00:00:00     \_ bash
7731 pts/0 00:00:00         \_ bash
7753 pts/0 00:00:00             \_ ps
$

 ps --forest命令展示了这些子 shell 间的嵌套结构

$ ps -f
UID PID PPID C STIME TTY TIME CMD
christi+ 7650 7649 0 16:01 pts/0 00:00:00 -bash
christi+ 7687 7650 0 16:02 pts/0 00:00:00 bash
christi+ 7709 7687 0 16:02 pts/0 00:00:00 bash
christi+ 7731 7709 0 16:02 pts/0 00:00:00 bash
christi+ 7781 7731 0 16:04 pts/0 00:00:00 ps -f
$
修改 shell 的启动方式

选 项           说明
-c string         从 string 中读取命令并进行处理
-i                 启动一个能够接收用户输入的交互式 shell
-l                 作为登录 shell 启动
-r                 启动一个受限 shell,将用户限制在默认目录中
-s                 从标准输入中读取命令

可以输入 man bash 获得关于 bash 命令的更多帮助信息,了解更多的命令行选项。

bash--help 命令也会提供一些额外的协助。
提示 如果想查看 bash shell 的版本号,在命令行中输出 bash --version 即可。该命令不会
创建子 shell,只会显示系统中 GNU bash shell 程序的当前版本。
可以使用 exit 命令有条不紊地退出子 shell:

$ ps -f
UID PID PPID C STIME TTY TIME CMD
christi+ 7650 7649 0 16:01 pts/0 00:00:00 -bash
christi+ 7687 7650 0 16:02 pts/0 00:00:00 bash
christi+ 7709 7687 0 16:02 pts/0 00:00:00 bash
christi+ 7731 7709 0 16:02 pts/0 00:00:00 bash
christi+ 8080 7731 0 16:35 pts/0 00:00:00 ps -f
$
$ exit
exit
$
$ ps --forest
PID TTY TIME CMD
7650 pts/0 00:00:00 bash
7687 pts/0 00:00:00 \_ bash
7709 pts/0 00:00:00 \_ bash
8081 pts/0 00:00:00 \_ ps
$
$ exit
exit
$ exit
exit
$
$ ps --forest
PID TTY TIME CMD
7650 pts/0 00:00:00 bash
8082 pts/0 00:00:00 \_ ps
$

exit 命令不仅能够退出子 shell,还可以注销(log out)当前的虚拟控制台终端或终端仿真器软件。只需在父 shell 中输入 exit,就能退出 CLI 。

5.2.1 查看进程列表

可以在单行中指定要依次运行的一系列命令。以分号(;)分隔即可:

$ pwd ; ls test* ; cd /etc ; pwd ; cd ; pwd ; ls my*
/home/christine
test_file test_one test_two
/etc
/home/christine
my_file my_scrapt my_script my_scrypt
$

在上面的例子中,所有命令依次执行,没有任何问题。不过这并不是进程列表。要想成为进
程列表,命令列表必须将命令放入圆括号内:

$ (pwd ; ls test* ; cd /etc ; pwd ; cd ; pwd ; ls my*)
/home/christine
test_file test_one test_two
/etc
/home/christine
my_file my_scrapt my_script my_scrypt
$

圆括号的加入使命令列表变成了进程列表,生成了一个子 shell 来执行这些命令。
注意 进程列表是命令分组(command grouping)的一种。另一种命令分组是将命令放入花括号
内,并在命令列表尾部以分号(;)作结。语法为:{ command; }。
使用花括号进行命令分组并不会像进程列表那样创建子 shell。
要想知道是否生成了子 shell,需要使用命令输出一个环境变量(参见第 6 章)的值。这个命
令就是 echo $BASH_SUBSHELL。如果该命令返回 0,那么表明没有子 shell。如果该命令返回 1
或者其他更大的数字,则表明存在子 shell。
下面这个例子先后使用了命令列表和 echo $BASH_SUBSHELL:

$ pwd ; ls test* ; cd /etc ; pwd ; cd ; pwd ; ls my* ; echo $BASH_SUBSHELL
/home/christine
test_file test_one test_two
/etc
/home/christine
my_file my_scrapt my_script my_scrypt
0
$

改用进程列表,则结果就不一样了。在列表最后加入 echo $BASH_SUBSHELL:

$ (pwd ; ls test* ; cd /etc ; pwd ; cd ; pwd ; ls my* ; echo $BASH_SUBSHELL)
/home/christine
test_file test_one test_two
/etc
/home/christine
my_file my_scrapt my_script my_scrypt
1
$

这次在输出结果的最后是数字 1。这表明的确创建了子 shell 来执行这些命令。
因此,进程列表就是使用圆括号包围起来的一组命令,它能够创建子 shell 来执行这些命令。

甚至可以在进程列表中嵌套圆括号来创建子 shell 的子 shell:

$ (pwd ; echo $BASH_SUBSHELL)
/home/Christine
1
$ (pwd ; (echo $BASH_SUBSHELL))
/home/Christine
2
$

注意,在第一个进程列表中,数字 1 表明有一个子 shell,这个结果和预期一样。但是在第
二个进程列表中,在命令 echo $BASH_SUBSHELL 之外又多出了一对圆括号。这对圆括号在子
shell 中产生了另一个子 shell 来执行该命令。数字 2 表示的就是这个子 shell。

子 shell 在 shell 脚本中经常用于多进程处理。但是,创建子 shell 的成本不菲(意思是要消耗
更多的资源,比如内存和处理能力),会明显拖慢任务进度。在交互式 CLI shell 会话中,子 shell
同样存在问题,它并非真正的多进程处理,原因在于终端与子 shell 的 I/O 绑定在了一起

5.2.2 子 shell 用法

在交互式 shell CLI 中,还有很多更富有成效的子 shell 用法。进程列表、协程和管道(参见
第 11 章)都用到了子 shell,各自都可以有效运用于交互式 shell。
在交互式 shell 中,一种高效的子 shell 用法是后台模式。在讨论如何配合使用后台模式和子
shell 之前,需要先搞明白什么是后台模式。

1. 后台模式

在后台模式中运行命令可以在处理命令的同时让出 CLI,以供他用。演示后台模式的一个典
型命令是 sleep。
sleep 命令会接受一个参数作为希望进程等待(睡眠)的秒数。该命令在 shell 脚本中常用
于引入一段暂停时间。命令 sleep 10 会将会话暂停 10 秒,然后返回 shell CLI 提示符

$ sleep 10
$

要想将命令置入后台模式,可以在命令末尾加上字符&。把 sleep 命令置入后台模式可以让
我们利用 ps 命令小窥一番:

$ sleep 3000&
[1] 2542
$
$ ps -f
UID       PID     PPID  C  STIME  TTY     TIME          CMD
christi+  2356   2352  0  13:27    pts/0    00:00:00    -bash
christi+  2542   2356  0  13:44    pts/0    00:00:00     sleep   3000
christi+  2543   2356  0  13:44    pts/0    00:00:00     ps        -f
$

sleep 命令会在后台(&)睡眠 3000 秒(50 分钟)。当其被置入后台时,在 shell CLI 提示
符返回之前,屏幕上会出现两条信息。

第一条信息是方括号中的后台作业号(1)。

第二条信息是后台作业的进程 ID(2542)。
ps 命令可以显示各种进程。注意进程列表中的 sleep 3000 命令。在其第二列显示的 PID
和该命令进入后台时所显示的 PID 是一样的,都是 2542。

jobs 命令

能够显示当前运行在后台模式中属于你的所有进程(作业):

$ jobs
[1]+ Running sleep 3000 &
$

jobs 命令会在方括号中显示作业号(1)。除此之外,还有作业的当前状态(Running)以
及对应的命令(sleep 3000 &)。

jobs -l

除了默认信息,-l选项还会显示命令的 PID。

$ jobs -l
[1]+ 2542 Running sleep 3000 &
$

如果运行多个后台进程,则还有一些额外信息可以显示哪个后台作业是最近启动的。

最近启动的作业在其作业号之后会有一个加号(+),在它之前启动的进程(the second newest process)则以减号(-)表示。
一旦后台作业完成,就会显示出结束状态:

$
[1]+ Done sleep 3000
$

后台模式用起来非常方便,为我们提供了一种在 CLI 中创建实用子 shell 的方法。

2. 将进程列表置入后台

通过将进程列表置入后台,可以在子 shell 中进行大量的多进程处理。由此带来的一个好处是终端不再和子 shell 的 I/O 绑定在一起。
之前说过,进程列表是子 shell 中运行的一系列命令。在进程列表中加入 sleep 命令并显示
BASH_SUBSHELL 变量,结果不出所料:

$ (sleep 2 ; echo $BASH_SUBSHELL ; sleep 2)
1
$

在上面的例子中,出现了 2 秒的暂停,显示的数字 1 表明只有一个子 shell,在返回提示符
之前又经历了另一个 2 秒的暂停。
将同样的进程列表置入后台会产生些许不同的命令输出:

$ (sleep 2 ; echo $BASH_SUBSHELL ; sleep 2)&
[1] 2553
$ 1
[1]+ Done ( sleep 2; echo $BASH_SUBSHELL; sleep 2 )
$

将进程列表置入后台会产生一个作业号和进程 ID,然后会返回提示符。不过,奇怪的是表
明一级子 shell(single-level subshell)的数字 1 竟然出现在了提示符的右边。别慌,按一下 Enter键(第3行),就会得到另一个提示符了。
在后台使用进程列表可谓是在 CLI 中运用子 shell 的一种创造性方法。可以用更少的键盘输
入换来更高的效率。

sleep 命令和 echo 命令组成的进程列表只是作为示例而已。使用 tar(参见第 4 章)
创建备份文件是有效利用后台进程列表的一个更实用的例子:

$ (tar -cf Doc.tar Documents ; tar -cf Music.tar Music)&
[1] 2567
$
$ ls *.tar
Doc.tar Music.tar
[1]+ Done ( tar -cf Doc.tar Documents; tar -cf Music.tar Music )
$

将进程列表置入后台并不是子 shell 在 CLI 中仅有的创造性用法,还有一种方法是协程。

3. 协程 coproc

协程同时做两件事:一是在后台生成一个子 shell,二是在该子 shell 中执行命令。
要进行协程处理,可以结合使用 coproc 命令以及要在子 shell 中执行的命令:

$ coproc sleep 10
[1] 2689
$

除了会创建子 shell,协程基本上就是将命令置入后台。当输入 coproc 命令及其参数之后,
你会发现后台启用了一个作业。屏幕上会显示该后台作业号(1)以及进程 ID(2689)。
jobs 命令可以显示协程的状态:

$ jobs
[1]+ Running coproc COPROC sleep 10 &
$

从上面的例子中可以看到,在子 shell 中执行的后台命令是 coproc COPROC sleep 10
COPROC 是 coproc 命令给进程起的名字。可以使用命令的扩展语法来自己设置这个名字:

$ coproc My_Job { sleep 10; }
[1] 2706
$
$ jobs
[1]+ Running coproc My_Job { sleep 10; } &
$

使用扩展语法,协程名被设置成了 My_Job。
在左花括号({)和内部命令名之间有一个空格。还必须保证内部命令以分号(;)结
尾。另外,分号和右花括号(})之间也得有一个空格。

注意 协程能够让你尽情地发挥想象力,发送或接收来自子 shell 中进程的信息。只有在拥有多
个协程时才需要对协程进行命名,因为你要和它们进行通信。否则的话,让 coproc 命令
将其设置成默认名称 COPROC 即可。

协程与进程列表结合

将协程与进程列表结合起来创建嵌套子 shell。只需将命令 coproc 放在进程列表之前即可:

$ coproc ( sleep 10; sleep 2 )
[1] 2750
$
$ jobs
[1]+ Running     coproc COPROC ( sleep 10; sleep 2 ) &
$
$ ps --forest
    PID  TTY       TIME CMD
    2367 pts/0 00:00:00 bash
    2750 pts/0 00:00:00   \_ bash
    2751 pts/0 00:00:00 |     \_ sleep
    2752 pts/0 00:00:00 \_ ps
$

生成子 shell 的成本可不低,而且速度很慢。创建嵌套子 shell 更是离谱
子 shell 提供了灵活性和便利性。要想获得这些优势,重要的是要理解子 shell 的行为方式。对于命令也是如此。下面将研究内建命令与外部命令之间的行为差异。

5.3 理解外部命令和内建命令

5.3.1 外部命令

外部命令(有时也称为文件系统命令)是存在于 bash shell 之外的程序。它并不
属于 shell 程序的一部分。外部命令程序通常位于/bin、/usr/bin、/sbin 或/usr/sbin 目录中。
ps 命令就是一个外部命令。可以使用 which 命令和 type 命令找到其对应的文件名:

$ which ps
/usr/bin/ps
$
$ type ps
ps is /usr/bin/ps
$
$ ls -l /usr/bin/ps
-rwxr-xr-x. 1 root root 142216 May 11 2019 /usr/bin/ps
$
衍生(forking)

每当执行外部命令时,就会创建一个子进程。

外部命令 ps会显示其父进程以及自己所对应的衍生子进程:

$ ps -f     
UID       PID PPID C STIME TTY       TIME CMD
christi+ 2367 2363 0 10:47 pts/0 00:00:00 -bash
christi+ 4242 2367 0 13:48 pts/0 00:00:00 ps -f
$

作为外部命令,ps 命令在执行时会产生一个子进程。在这里,ps 命令的 PID 是 4242,
父 PID 是 2367。作为父进程的 bash shell 的 PID 是 2367。下图 展示了外部命令执行时的衍生过程。

无论是衍生出子进程还是创建了子 shell,都仍然可以通过信号与其互通,这一点无论是
在使用命令行还是在编写脚本时都极其有用。进程间以发送信号的方式彼此通信。第 16 章将介绍信号和信号发送。 

5.3.2 内建命令

与外部命令不同,内建命令无须使用子进程来执行。
cd 命令和 exit 命令都内建于 bash shell。可以使用 type 命令来判断某个命令是否为内建:

$ type cd
cd is a shell builtin
$
$ type exit
exit is a shell builtin
$

内建命令既不需要通过衍生出子进程来执行,也不用打开程序文件,所以执行速度更快,
效率也更高。附录 A 给出了 GNU bash shell 的内建命令清单。
注意,有些命令有多种实现。例如,echo 和 pwd 既有内建命令也有外部命令。两种实现略
有差异。要查看命令的不同实现,可以使用 type 命令的-a 选项:

$ type -a echo
echo is a shell builtin
echo is /usr/bin/echo
$
$ which echo
/usr/bin/echo
$
$ type -a pwd
pwd is a shell builtin
pwd is /usr/bin/pwd
$
$ which pwd
/usr/bin/pwd
$

type -a 命令显示出了每个命令的两种实现(内建和外部)。

which 命令只显示外部命令文件。

提示 对于有多种实现的命令,如果想使用其外部命令实现,直接指明对应的文件即可。例
如,要使用外部命令 pwd,可以输入/usr/bin/pwd。

1. 使用 history 命令

history是一个实用的内建命令,能帮助你管理先前执行过的命令。
要查看最近用过的命令列表,可以使用不带任何选项的 history 命令:

$ history
1 ps -f
2 pwd
3 ls
[...]
$

可以设置保存在 bash 历史记录中的命令数量。为此,需要修改名为 HISTSIZE 的环境变量

输入!!,然后按 Enter 键,唤回并重用最近那条命令:

$ ps --forest
PID TTY TIME CMD
2367 pts/0 00:00:00 bash
5240 pts/0 00:00:00 \_ ps
$
$ !!
ps --forest
PID TTY TIME CMD
2367 pts/0 00:00:00 bash
5241 pts/0 00:00:00 \_ ps
$

当输入!!时,bash 会先显示从 shell 的历史记录中唤回的命令,然后再执行该命令。
命令历史记录被保存在位于用户主目录的隐藏文件.bash_history 之中:

$ pwd
/home/christine
$
$ ls .bash_history
.bash_history
$

在 CLI 会话期间,bash 命令的历史记录被保存在内存中。当 shell 退出时才被写入历史文件

history 命令运行时所显示的最近命令与.bash_history 文件中最后的命令并不一致。
有 6 个已经执行过的命令并没有被记录在历史文件中。
可以在不退出 shell 的情况下强制将命令历史记录写入.bash_history 文件。为此,需要使用

history -a
history -a

如果打开了多个终端会话,则仍然可以使用 history -a 命令在每个打开的会话中向.bash_history 文件添加记录。但是历史记录并不会在其他打开的终端会话中自动更新。
这是因为.bash_history 文件只在首次启动终端会话的时候才会被读取。要想强制重新读
取.bash_history 文件,更新内存中的终端会话历史记录,可以使用

history -n 

可以唤回历史记录中的任意命令。

!42
$ history
1 ps -f
2 pwd
[...]
39 history
40 cat .bash_history
41 ps --forest
42 pwd
43 ps -f
44 history
45 cat .bash_history
46 history -a
47 history
48 cat .bash_history
49 history
$
$ !42
pwd
/home/christine
$

bash shell 会先显示从历史记录中唤回的命令,然后再执行该命令。

history -c

清除命令历史,很简单,输入 history -c即可。

接下来再输入 history-a,清除 .bash_history 文件。

最后可以通过 man history 来查看 history 命令的 bash 手册页

2. 使用命令别名
alias 命令

另一个实用的 shell 内建命令。命令别名允许为常用命令及其参数创建另一个名称,从而将输入量减少到最低。
你所使用的 Linux 发行版很有可能已经为你设置好了一些常用命令的别名。

alias -p 查看当前可用的别名:
$ alias -p
[...]
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'
$

注意,在该 Ubuntu Linux 发行版中,有一个别名取代了标准命令 ls。该别名中加入了
--color=auto 选项,以便在终端支持彩色显示的情况下,ls 命令可以使用色彩编码(比如,使用蓝色表示目录)。LS_COLORS 环境变量(环境变量相关内容见第 6 章)控制着所用的色彩编码。

提示 如果经常跳转于不同的发行版,那么在使用色彩编码来分辨某个名称究竟是目录还是
文件时,一定要小心。因为色彩编码并未实现标准化,所以最好使用 ls -F 来判断文件类型。

alias li='ls -i 创建自己的别名:
$ alias li='ls -i
$
$ li
34665652 Desktop 1415018 NetworkManager.conf
1414976 Doc.tar 50350618 OldDocuments
34665653 Documents 1414981 Pictures
51693739 Downloads 16789591 Public
1415016 hlink_test_one 1415019 really_ridiculously_long_file_name
1415021 log_file 1415020 slink_test_file
51693757 Music 1415551 Templates
1414978 Music.tar 1415523 test_file
1415525 my_file 1415016 test_one
1415524 my_scrapt 1415017 test_two
1415519 my_script 16789592 Videos
1415015 my_scrypt
$

定义好别名之后,就可以随时在 shell 或者 shell 脚本中使用了。要注意,因为命令别名属于
内建命令,所以别名仅在其被定义的 shell 进程中才有效。

$ alias li='ls -i'
$
$ bash
$ li
bash: li: command not found...
$
$ exit
exit
$
$ li
34665652 Desktop 1415018 NetworkManager.conf
1414976 Doc.tar 50350618 OldDocuments
[...]
1415524 my_scrapt 1415017 test_two
1415519 my_script 16789592 Videos
1415015 my_scrypt
$

可以在命令行中输入 unalias alias-name 删除指定的别名。如果被删除的别名不是你设置的,那么等下次重新登录系统的时候,该别名就会再次出现。可以通过修改环境文件永久地删除某个别名。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值