Linux内部命令和外部命令

关于上篇777超级目录权限下的测试有不严谨的地方(最终结果不受影响),这部分知识点遗忘的厉害,所以特别总结这篇文章。 
上篇文章中最大的问题是忽略了BASH的内部命令和外部命令,本篇文章重点论述Linux内部命令和外部命令的相关知识体系。 
echo为例,下面三种方式执行方式是有很大区别的

# 方式一
enable echo
echo "abc"
# 方式二
enable -n echo
echo "abc"
# 方式三
/bin/echo
  • 方式一 
    默认调用的是BASH SHELL内置命令echo来直接运行该命令,无需fock子shell。

  • 方式二 
    执行enable -n echo关闭BASH SHELL内部echo命令,即根据系统环境变量顺序查找echo命令,而后执行。

  • 方式三 
    该方式,无需查找环境变量,而是直接执行/bin/echo命令。

那么Linux下究竟如何查找并运行命令呢?什么是内部命令和外部命令,为什么会有内部命令和外部命令?如何区别内部命令和外部命令呢?我们逐一来看

1. 什么是内部命令和外部命令

Linux命令有内部(建)命令和外部命令之分,内部命令和外部命令功能基本相同,但有些细微差别。所谓的内部和外部其实是相对SHELL自身来讲。Linux系统为了提高系统运行效率,将经常使用的轻量的命令在系统启动时一并加载这些命令到内存中供SHELL随时调用,这部分命令即为内部命令。反之,系统层调用的较重的命令只有当被调用时才会硬盘加载的这部分命令即为外部命令。

  • (1)内部命令实际上是shell程序的一部分,其中包含的是一些比较简单的linux系统命令,这些命令由shell程序识别并在shell程序内部完成运行,通常在linux系统加载运行时shell就被加载并驻留在系统内存中。内部命令是写在bashy源码里面的,其执行速度比外部命令快,因为解析内部命令shell不需要创建子进程。比如:exit,history,cd,echo等。

  • (2)外部命令是linux系统中的实用程序部分,因为实用程序的功能通常都比较强大,所以其包含的程序量也会很大,在系统加载时并不随系统一起被加载到内存中,而是在需要时才将其调用内存。通常外部命令的实体并不包含在shell中,但是其命令执行过程是由shell程序控制的。shell程序管理外部命令执行的路径查找、加载存放,并控制命令的执行。外部命令是在bash之外额外安装的,通常放在/bin,/usr/bin,/sbin,/usr/sbin……等等。可通过“echo $PATH”命令查看外部命令的存储路径,比如:ls、vi等。

2. 如何区别内部命令和外部命令

日常工作中,对于系统用户来讲其实很少关注内部命令和外部命令,只要使得顺手正常,很少有人去关注这部分内容。但在环境复杂或系统状态异常(被入侵)等情况下,我们更建议使用绝对路径下的外部命令。当然,Linux系统也提供了相关命令来区别二者,type区分内部命令与外部命令。 
用法如下:

type: type [-afptP] name [name ...]
   Display information about command type.

   For each NAME, indicate how it would be interpreted if used as a
   command name.

   Options:
     -a        display all locations containing an executable named NAME;
       includes aliases, builtins, and functions, if and only if
       the `-p' option is not also used
     -f        suppress shell function lookup
     -P        force a PATH search for each NAME, even if it is an alias,
       builtin, or function, and returns the name of the disk file
       that would be executed
     -p        returns either the name of the disk file that would be executed,
       or nothing if `type -t NAME' would not return `file'.
     -t        output a single word which is one of `alias', `keyword',
       `function', `builtin', `file' or `', if NAME is an alias, shell
       reserved word, shell function, shell builtin, disk file, or not
       found, respectively

   Arguments:
     NAME      Command name to be interpreted.

   Exit Status:
   Returns success if all of the NAMEs are found; fails if any are not found.

常用的三个参数:

-t对应-type 
 -a对应-all 
 -p对应-path

使用:type [-a | -t | -p] name 或 type [-all | -type | -path] name。

  • (1)没有参数的状况下,它会显示出shell如何解译name做为命令。

  • (2)如果有”-type”,它将会显示alias、 keyword、function、builtin或file。 

    • file:表示为外部指令;

    • alias:表示该指令为命令别名所设定的名称;

    • builtin:表示该指令为 bash 内建的指令功能。

  • (3)如果有”-path”的参数,它将会显示该命令的完整档名(外部指令)或显示为内建指令,找不到的话,不显示任何东西。

  • (4)如果有”-all”的参数,会将由PATH变量定义的路径中所有含有name指令的路径都列出来,即显示所有可执行name的可能路径。

例如1:

[%23%root@192 ~]# type cd
cd is a shell builtin #这里可以看出cd是一个内部命令  

例如2:

[%24%root@192 ~] type ls  
ls is aliased to `ls --color=auto' # 没有加上任何参数,仅列出 ls 这个指令的最主要使用情况  
[%25%root@192 ~] type -t ls  
alias # -t 参数则仅列出 ls 这个指令的最主要使用情况说明  

例如3:

[%26%root@192 ~] type -a ls  
ls is aliased to `ls --color=auto'  
ls is /bin/ls # 列出所有信息:这里可以看出ls是一个外部命令。  


3. 为什么会内部命令和外部命令

内部命令其实是SHELL程序的一部分,其中包含的是一些比较简练和日常经常会被用到的命令。这些命令通常系统启动时就调入内存,且常驻内存的,由SHELL程序识别并在SHELL程序内部运行,之所以这样做的原因只有一个就是:为了最大化执行效率,提升系统性能。而 外部命令通常是系统的软件功能,该部分程序功能通常较为强大,但包括的程序量也很大,因此并不随系统启动一并加载,只在用户需要时才从硬盘中读入内存。

4. 内部命令和外部命令的区别

因为内部命令是SHELL内置,所以该命令调用时直接使用,无需追踪环境变量,而外部命令则有很大区别,因为外部命令如希望被用户所使用,依然要通过SHELL程序来调用,所以多了一层执行路径的问题,即我们常讲到的环境变量。

外部命令就是由Shell副本(新的进程)所执行的命令,基本的过程如下:

  • a. 建立一个新的进程。此进程即为Shell的一个副本。

  • b. 在新的进程里,在PATH变量内所列出的目录中,寻找特定的命令。 
     /bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin为PATH变量典型的默认值。 
     当命令名称包含有斜杠(/)符号时,将略过路径查找步骤。

  • c. 在新的进程里,以所找到的新程序取代执行中的Shell程序并执行。

  • d. 程序完成后,最初的Shell会接着从终端读取下一条命令,和执行脚本里的下一条命令。

通常情况下,脚本中的Bash内建命令在运行的时候是不会fork出一个子进程的。但是脚本中的外部或者过滤命令通常会fork出一个子进程。 一个内建命令通常会与一个系统命令同名,但是Bash在内部重新实现了这些命令。比如,Bash的echo命令与/bin/echo就不尽相同,虽然它们的行为在绝大多数情况下都是一样的。

同理,如果我们内部命令对应的外部存放mv到系统环境变量之外的其它目录下或者rm掉。该命令其实仍然可以被执行的,因为其查找的顺序是内部命令->外部命令,看下面的这个小实验:

[%27%root@192 ~]# which cd
/usr/bin/cd  ## 外部cd二进制文件存放在该目录下
[%28%root@192 ~]# mv /usr/bin/cd /usr/bin/cd.move   ## 改名
[%29%root@192 ~]# cd /usr/   ## 改名后依然可以正常执行
[%30%root@192 /usr]# cd -
/root
[%31%root@192 ~]# type cd
cd is a shell builtin   ## cd 是内部命令


shell命令解释器在执行命令时,先尝试按照内部命令来执行,如果要执行的命令不是内部命令,则按照外部命令去查找对应的执行文件所在的目录,并执行。当要执行的命令不是内部命令时(例如ls),如果有两个ls指令分别在不同的目录中(例如/usr/local/bin/ls和/bin/ls),shell命令解释器就根据PATH里面哪个目录先被查询到,则那个目录下的命令就先被执行。

5. 查看和关闭内部命令

SHELL中的内置命令约有60个,通过内置的enable命令即可查看所有的内部命令

[%66%root@192 ~]# enable 
enable .
enable :
enable [
enable alias
enable bg
enable bind
enable break
enable builtin
enable caller
enable cd
enable command
enable compgen
enable complete
enable compopt
enable continue
enable declare
enable dirs
enable disown
enable echo
enable enable
enable eval
enable exec
enable exit
enable export
enable false
enable fc
enable fg
enable getopts
enable hash
enable help
enable history
enable jobs
enable kill
enable let
enable local
enable logout
enable mapfile
enable popd
enable printf
enable pushd
enable pwd
enable read
enable readarray
enable readonly
enable return
enable set
enable shift
enable shopt
enable source
enable suspend
enable test
enable times
enable trap
enable true
enable type
enable typeset
enable ulimit
enable umask
enable unalias
enable unset
enable wait

其中内部命令没有专门的man文档和help说明。即执行如下命令不会得到想要的帮助文档

[%73%root@192 ~]# cd -h
-bash: cd: -h: invalid option
cd: usage: cd [-L|[-P [-e]]] [dir]
[%74%root@192 ~]# cd --help
-bash: cd: --: invalid option
cd: usage: cd [-L|[-P [-e]]] [dir]
[%75%root@192 ~]# man cd
BASH_BUILTINS(1)              General Commands Manual             BASH_BUILTINS(1)

NAME
      bash,  :, ., [, alias, bg, bind, break, builtin, caller, cd, command, comp‐
      ....
      内容较多,不一一列举

一般内部命令使用help COMMAND如下命令获取帮助文档

# help command

enable命令为例:

[%77%root@192 ~]# help enable
enable: enable [-a] [-dnps] [-f filename] [name ...]
   Enable and disable shell builtins.

   Enables and disables builtin shell commands.  Disabling allows you to
   execute a disk command which has the same name as a shell builtin
   without using a full pathname.

   Options:
     -a        print a list of builtins showing whether or not each is enabled
     -n        disable each NAME or display a list of disabled builtins
     -p        print the list of builtins in a reusable format
     -s        print only the names of Posix `special' builtins

   Options controlling dynamic loading:
     -f        Load builtin NAME from shared object FILENAME
     -d        Remove a builtin loaded with -f

   Without options, each NAME is enabled.

   To use the `
test' found in $PATH instead of the shell builtin
   version, type `enable -n test'
.

   Exit Status:
   Returns success unless NAME is not a shell builtin or an error occurs.

enable -n cd 表示禁用命令cd在SHELL中的内置功能。

[%88%root@192 ~]# cd /usr/bin/
[%89%root@192 /usr/bin]# mv cd cd.move
[%90%root@192 /usr/bin]# pwd
/usr/bin
[%91%root@192 /usr/bin]# enable  -n cd
[%92%root@192 /usr/bin]# cd /tmp
-bash: /usr/bin/cd: No such file or directory
[%93%root@192 /usr/bin]# enable cd
[%94%root@192 /usr/bin]# cd /tmp
[%95%root@192 /tmp]# pwd
/tmp

Linux内部命令和外部命令_java

OK,至此内部命令和外部命令希望我讲的还算明白