初识Shell

运行方式


我的test.sh文件

#!/bin/bash
ls
pwd
date

第一种,为当前文件加上可执行权限,作为可执行文件,需要给代码第一行加上 #!/bin/bash

$ chmod +x test.sh

$ ./test.sh

 

cgdb        Desktop    googletest-release-1.8.0  Pictures   test.sh

cgdb-0.7.0  Documents  HTTP             Public     Videos

class        Downloads  Music             Templates  webbench-1.5

/home/jin

Fri Aug 24 13:30:07 EDT 2018

  • 注意,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当 前目录找。

 

第二种,作为解释器的参数,这种可以不加可执行权限,也不需要给代码第一行加上 #!/bin/bash 的shebang

$ /bin/bash test.sh

 

cgdb        Desktop    googletest-release-1.8.0  Pictures   test.sh

cgdb-0.7.0  Documents  HTTP             Public     Videos

class        Downloads  Music             Templates  webbench-1.5

/home/jin

Fri Aug 24 13:35:00 EDT 2018

  • 这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名,这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。

  • Shell脚本中用#表示注释,相当于C语言的//注释。

  • 但如果#位于第一行开头,并且是则例外,它表示该脚本使用后面指定的解释器/bin/bash解释执行。

 

shell原理


初识Shell_第1张图片

还是以上面的 test.sh 为例,当我们在命令行敲下 ./text.sh 或者 /bin/bash test.sh 的时候其实发生了下面的事

  • Shell(父进程)首先创建子进程,接着子进程再去 exec 可执行文件,其实 exec 以后是在运行解释器

  • 父进程等待子进程执行结束

  • 子进程任务

    • 打开文件,按行读取

    • 读取第一行

      • fork孙子进程

      • 孙子进程exec

    • 孙子进程执行完成,返回,子进程读取下一行

      • fork孙子进程

      • 孙子继承exec

    • ...直到执行完当前test.sh文件中的指令

    • 子进程返回

  • 父进程等待结束,整个shell执行完成

 

解释内建指令的执行原理


现在将 test.sh 内容修改如下

#!/bin/bash
pwd
cd ..
pwd

我们要得到的效果是,第二次 pwd 是第一次 pwd 的上级目录

 

脚本执行cd命令,发现回显消息当前所处的目录发生改变,但实际上,真实目录并没有改变。这个也很好理解,毕竟要创建子进程来解释脚本。但是:

 

直接命令行上执行 cd 命令,发现父bash的工作目录发生了改变!这个如何理解?说好的创建子进程呢?归根结底,执行命令,不一定要创建子进程这些不需要创建子进程的命令,叫做shell的内建命令,由父bash亲自执 行,理解上,将该类命令,理解成shell的内部函数即可。 可是

 

我们发现,用 . 或者 source 修饰脚本,脚本的执行影响到了父bash!source或者 . 命令是Shell的内建命令,这种方式也不会创建子Shell,而是直接在交互式Shell下逐行执行脚本中的命令

 

Linux 上的内建指令


可以 man cd,因为 cd 本身就是一个内建命令

初识Shell_第2张图片

 

 

你可能感兴趣的:(初识Shell)