以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。
一、总结
(1)由博文shell的概念与作用第四点可知,shell命令分为内置命令、外部命令。
由 Shell 这个程序自带的命令称为内置命令,它在 Shell 内部可以通过函数来实现,当 Shell 启动后,这些命令所对应的代码(函数体代码)就已经被加载到内存中了,所以使用内置命令是非常快速的。
而那些 Shell 外部命令,它们的本质就是文件系统中的一个个可执行文件,或者说应用程序,一个命令就对应一个应用程序,执行一个外部命令就是启动一个新的应用程序。运行外部命令要创建一个新的进程,并加载应用程序的代码,所以效率上比内置命令差很多。
(2)外部命令所对应的应用程序,入口地址是main函数。从这个角度来看,我们就不再区分函数和应用程序了,即不管是内置命令还是外部命令,shell命令的选项与参数,最终都是以参数的形式传给了函数。某个shell命令对应着某个函数,shell命令的选项与参数对应着某个函数的参数。
(3)$PATH 变量包含的目录中几乎聚集了系统中绝大多数的可执行命令,它们都是外部命令。
(4)通常来说,内建命令会比外部命令执行得更快,执行外部命令时不但会触发磁盘 I/O,还需要 fork 出一个单独的进程来执行,执行完成后再退出。而执行内建命令相当于调用当前 Shell 进程的一个函数。
二、内置命令
(1)Shell 是一个常驻内存的程序,因此内置命令不宜过多,过多的内置命令会导致 Shell 程序本身体积膨胀,运行 Shell 程序后就会占用更多的内存,而占用过多内存会影响其它的程序。
(2)只有那些最常用的命令才有理由成为内置命令,比如 cd、kill、echo 等。
(3)我们可以使用 type 来确定一个命令是否是内建命令。如下所示,可知 cd 是一个 Shell 内建命令,而 ifconfig 是一个外部文件,它的位置是/sbin/ifconfig
。
xjh@ubuntu:~/iot/tmp$ type cd
cd is a shell builtin
xjh@ubuntu:~/iot/tmp$ type ifconfig
ifconfig is /sbin/ifconfig
xjh@ubuntu:~/iot/tmp$
(4)常见的内部命令列表如下所示。
命令 | 说明 |
---|---|
: | 扩展参数列表,执行重定向操作 |
. | 读取并执行指定文件中的命令(在当前 shell 环境中) |
alias | 为指定命令定义一个别名 |
bg | 将作业以后台模式运行 |
bind | 将键盘序列绑定到一个 readline 函数或宏 |
break | 退出 for、while、select 或 until 循环 |
builtin | 执行指定的 shell 内建命令 |
caller | 返回活动子函数调用的上下文 |
cd | 将当前目录切换为指定的目录 |
command | 执行指定的命令,无需进行通常的 shell 查找 |
compgen | 为指定单词生成可能的补全匹配 |
complete | 显示指定的单词是如何补全的 |
compopt | 修改指定单词的补全选项 |
continue | 继续执行 for、while、select 或 until 循环的下一次迭代 |
declare | 声明一个变量或变量类型。 |
dirs | 显示当前存储目录的列表 |
disown | 从进程作业表中刪除指定的作业 |
echo | 将指定字符串输出到 STDOUT |
enable | 启用或禁用指定的内建shell命令 |
eval | 将指定的参数拼接成一个命令,然后执行该命令 |
exec | 用指定命令替换 shell 进程 |
exit | 强制 shell 以指定的退出状态码退出 |
export | 设置子 shell 进程可用的变量 |
fc | 从历史记录中选择命令列表 |
fg | 将作业以前台模式运行 |
getopts | 分析指定的位置参数 |
hash | 查找并记住指定命令的全路径名 |
help | 显示帮助文件 |
history | 显示命令历史记录 |
jobs | 列出活动作业 |
kill | 向指定的进程 ID(PID) 发送一个系统信号 |
let | 计算一个数学表达式中的每个参数 |
local | 在函数中创建一个作用域受限的变量 |
logout | 退出登录 shell |
mapfile | 从 STDIN 读取数据行,并将其加入索引数组 |
popd | 从目录栈中删除记录 |
printf | 使用格式化字符串显示文本 |
pushd | 向目录栈添加一个目录 |
pwd | 显示当前工作目录的路径名 |
read | 从 STDIN 读取一行数据并将其赋给一个变量 |
readarray | 从 STDIN 读取数据行并将其放入索引数组 |
readonly | 从 STDIN 读取一行数据并将其赋给一个不可修改的变量 |
return | 强制函数以某个值退出,这个值可以被调用脚本提取 |
set | 设置并显示环境变量的值和 shell 属性 |
shift | 将位置参数依次向下降一个位置 |
shopt | 打开/关闭控制 shell 可选行为的变量值 |
source | 读取并执行指定文件中的命令(在当前 shell 环境中) |
suspend | 暂停 Shell 的执行,直到收到一个 SIGCONT 信号 |
test | 基于指定条件返回退出状态码 0 或 1 |
times | 显示累计的用户和系统时间 |
trap | 如果收到了指定的系统信号,执行指定的命令 |
type | 显示指定的单词如果作为命令将会如何被解释 |
typeset | 声明一个变量或变量类型。 |
ulimit | 为系统用户设置指定的资源的上限 |
umask | 为新建的文件和目录设置默认权限 |
unalias | 刪除指定的别名 |
unset | 刪除指定的环境变量或 shell 属性 |
wait | 等待指定的进程完成,并返回退出状态码 |
三、外部命令
(1)一个外部的应用程序是如何变成一个 Shell 命令的呢?
应用程序就是一个文件,只不过这个文件是可以执行的。既然是文件,那么它就有一个名字,并且存放在文件系统中。用户在 Shell 中输入一个外部命令后,只是将可执行文件的名字告诉了 Shell,但是并没有告诉 Shell 去哪里寻找这个文件。
难道 Shell 要遍历整个文件系统,查看每个目录吗?这显然是不能实现的。
为了解决这个问题,Shell 在启动文件中增加了一个叫做 PATH 的环境变量,该变量就保存了 Shell 对外部命令的查找路径,如果在这些路径下找不到同名的文件,Shell 也不会再去其它路径下查找了,它就直接报错。
(2)我们可以使用 echo 命令输出 PATH 变量的值,查看它保存着哪些检索路径,而Shell 只会在它指定的几个固定的路径中查找外部命令。