1. shell 概念
1.1 shell
shell(壳, 一种用C 语言编写的程序)是一个命令行解释器,是linux内核的一个外壳, 负责外界与linux内核的交互。
shell 是连接 用户与 Unix/Linux内核的桥梁,它通过调用系统核心的大部分功能的形式向用户隐藏了系统的底层细节,它通过建立文件的形式并行的运行多个程序,来帮助用户完成很多工作。
shell接收用户或者其他应用程序的命令, 然后将这些命令转化成内核能理解的语言并传给内核, 内核执行命令完成后将结果返回给用户或者应用程序。
Shell既是一种命令语言,又是一种程序设计语言。
但是Shell是不需要进行编译的,它是从脚本程序中一行一行的读取并执行命令。
Shell是Linux学习过程中很重要的一部分, 它有两种执行命令的方式:
- 交互式(Interactive),用户输入一条命令,Shell就解释执行一条;
- 批处理(Batch),用户事先写一个Shell脚本(Script),其中有很多条命令,让Shell一次把这些命令执行完,而不必一条一条地敲命令。
1.2 shell 的种类
Linux系统下有多种Shell可以供我们选择,常见的有Bourne Again Shell (简称bash)、Bourne Shell(简称sh)、C-Shelll(简称csh)、Korn Shell(简称ksh)。
我们可以通过查看/etc/shells文件中的内容来查看当前主机中包含哪些类型的Shell,
cat /etc/shells
~/clash$ cat /etc/shells
/bin/sh
/bin/bash
/bin/rbash
/bin/dash
通过echo $SHELL 命令来查看当前使用的Shell类型。
:~/clash$ echo $SHELL
/bin/bash
下面我们进行一些常见Shell的讲解: (1) BourneShell(sh):是由AT&T Bell实验室的 Steven Bourne为AT&T的Unix开发的,它是Unix的默认Shell,也是其它Shell的开发基础。Bourne Shell在编程方面相当优秀,但在处理与用户的交互方面不如其它几种Shell。
(2) BourneAgain Shell (即bash):是自由软件基金会(GNU)开发的一个Shell,它是Linux系统中一个默认的Shell。Bash不但与Bourne Shell兼容,还继承了C Shell、Korn Shell等优点。
(3) ash:ash Shell是由Kenneth Almquist编写的,是Linux 中占用系统资源最少的一个小Shell,它只包含24个内部命令,因而使用起来很不方便。
(4) CShell(csh):是加州伯克利大学的Bill Joy为BSD Unix开发的,共有52个内部命令,与sh不同,它的语法与C语言很相似。它提供了Bourne Shell所不能处理的用户交互特征,如命令补全、命令别名、历史命令替换等。但是,C Shell与BourneShell并不兼容。该Shell其实是指向/bin/tcsh这样的一个Shell,也就是说,csh其实就是tcsh。
(5) KornShell(ksh):是AT&T Bell实验室的David Korn开发的,共有42 条内部命令,它集合了C Shell和Bourne Shell的优点,并且与Bourne Shell向下完全兼容。Korn Shell的效率很高,其命令交互界面和编程交互界面都很好。
(6) zch:是Linux 最大的Shell之一,由Paul Falstad完成,共有84 个内部命令。如果只是一般的用途,没有必要安装这样的Shell。
注释:bash是 Bourne Again Shell 的缩写,是linux标准的默认shell ,它基于Bourne shell,吸收了C shell和Korn shell的一些特性。bash完全兼容sh,也就是说,用sh写的脚本可以不加修改的在bash中执行。
1.3 terminal
终端(termimal),作用是提供一个命令的输入输出环境,在linux下使用组合键ctrl+alt+T打开的就是终端。
1.4 终端与 shell 的关系
当你打开一个terminal时,操作系统会将terminal和shell关联起来,当我们在terminal中输入命令后,shell就负责解释命令。
2. 脚本的概念
简单的来说,脚本是包含一系列要执行的命令。 这些命令由解释器执行。
一切你可以在命令行中输入的命令,你都可以把它放到脚本中。 而且,脚本非常适合自动化任务。如果你发现自己频繁重复一些命令,你可以创建一个脚本来实现它!
而 shell 脚本,是一种为shell 编写的脚本程序;
编写的要点参考
2.1 shell 脚本的编写
方法一:
-
使用 cat 命令创建一个名为 hello.sh的新文件: cat > hello.sh -
继续上面,在终端中键入以下内容: echo 'Hello, World!'
上面的代码作用,是在使用echo 命令来打印“Hello World”。 可以直接在终端中使用此命令,但在本测试中,将通过 shell 脚本运行此命令。
- 按 Ctrl+D 将文本保存到文件中,同时从 cat 命令中出来。
你还可以使用基于终端的文本编辑器,如 Vim、Emacs或 Nano。如果你使用的是桌面 Linux,还可以使用图形文本编辑器(如 Gedit)将文本添加到此文件中。
-
使用 chmod 命令使文件 hello.sh 可执行,如下所示: chmod u+x hello.sh -
最后,通过在 hello.sh 前面加上“bash”来运行你的第一个 shell 脚本:bash hello.sh
方法二:
打开文本编辑器(可以使用 vi/vim 命令来创建文件),新建一个文件 test.sh,扩展名为 sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好,如果你用 php 写 shell 脚本,扩展名就用 php 好了。
输入一些代码,第一行一般是这样:
#!/bin/bash
echo "Hello World !"
其中:
-
#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。 -
echo 命令用于向窗口输出文本。
2. 2运行shell 脚本的两种方法
1、作为可执行程序
将代码保存为 test.sh,并 cd 到相应目录:
chmod +x ./test.sh
./test.sh
注意,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找。
2、作为解释器参数
这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名, 如:
/bin/sh test.sh
/bin/php test.php
这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。
2. 3 将shell 脚本转换为 bash 脚本
Bash是“Bourne-Again shell”的缩写,它只是 Linux 中许多可用 shell 的一种。
-
shell 是一个命令行解释器,它接受并运行命令。如果你以前运行过任何 Linux 命令,那么你已经使用过 shell。当你在 Linux 中打开终端时,你已经在运行系统的默认 shell。 -
Bash 通常是大多数 Linux 发行版中的默认 shell。这就是为什么 bash 通常是 shell 的同义词。Shell 只是一个程序,而 bash 是它的一个实现。还有其他这样的 shell 程序,如 ksh、zsh等。如果你安装了其他 shell,你也可以使用它来代替 bash。
shell 脚本通常具有几乎相同的语法,但有时也会有所不同。例如,数组索引在 Zsh 中从 1 开始,而不是在 bash 中从 0 开始。如果为Zsh shell编写的脚本有数组,则它在 bash 中将无法正常工作。
为了避免这种错误,
应该告诉解释器你的 shell 脚本是为 bash shell 编写的。 通过在脚本开头,添加 #! 来实现;
2. 3 .1 #! 作用
“#!/bin/bash ”这一行被称为shebang 行,在某些文献中,它被称为hashbang 行,这是因为它以两个字符hash '#' 和bang '!' 开头。
#! /bin/bash
echo 'Hello, World!'
当你在脚本的最顶部包含“#!/bin/bash” 行时,系统知道你想使用 bash 作为脚本的解释器。因此,你现在可以直接运行 hello.sh 脚本,而无需在其前面加上 bash。
使用 #!/bin/bash 表示该脚本是 bash shell 脚本,无论系统上正在使用什么 shell,都应该使用 bash 作为解释器运行。如果你使用的是 zsh 特定的语法,你可以通过添加 #! /bin/zsh 作为脚本的第一行。
#! 和 /bin/bash 之间的空格无关紧要。你也可以使用 #!/bin/bash 。
2. 3 .2将 shell 脚本添加到 PATH
(以便它可以从任何目录运行)
前面使用 ./hello.sh 来运行脚本;如果省略前导 ./
Bash 认为你正在尝试运行名为 hello.sh 的命令。当你在终端上运行任何命令时,shell 就在存储在PATH 变量中的一组目录中查找该命令。
可以使用echo 查看该 PATH 变量的内容:
echo $PATH
~/Documents/course_2610/lab7_shell/scripts$ echo $PATH
/home/respecting-god/anaconda3/condabin:/usr/local/cuda-11.2/bin:/home/respecting-god/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
冒号字符 (: ) 分隔每次运行命令时 shell 扫描的每个目录的路径。
像 echo、cat 等 Linux 命令可以从任何地方运行,因为它们的可执行文件存储在 bin 目录中。bin 目录包含在 PATH 中。当你运行命令时,系统会检查 PATH 以查找它应该寻找的所有可能位置,以找到该命令的可执行文件。
如果你想从任何地方运行你的 bash 脚本,就像它是一个常规的 Linux 命令,需要将你的 shell 脚本的位置添加到 PATH 变量中。
- 首先,获取脚本目录的位置(假设在同一目录中),使用 PWD 命令:
pwd - 使用 export 命令将脚本目录添加到 PATH 变量。
exportPATH=$PATH:/home/respectinggod/Documents/course_2610/lab7_shell/scripts
运行 hello.sh :
3. Shell 实现模拟多进程并发执行
这里通过将任务置为,后台执行, 来实现多进程的并发执行;
3.1 正常情况的脚本
我们就实现一种情况, 顺序执行,没有并发执行时:
这种情况下, 程序顺序执行, 每个循环大约执行 1 s 中; 总共15 个循环, 执行完成 15 s 左右;
cat > test1.sh 输入以下代码内容:
for((i = 0; i<15; i++)); do
{
sleep 1; echo 1 >>aa && echo "done!"
}
done
cat aa|wc -l
rm aa
执行 time bash test1.sh 运行test1.sh 程序
$ time bash test1.sh
done!
done!
done!
done!
done!
done!
done!
done!
done!
done!
done!
done!
done!
done!
done!
15
real 0m15.046s
user 0m0.023s
sys 0m0.026s
3.2 模拟多进程的脚本
在bash中,使用后台任务来实现任务的“多进程化”。 在不加控制的模式下,不管有多少任务,全部都后台执行。 也就是说,在这种情况下,有多少任务就有多少“进程”在同时执行。
for((i = 0; i<15; i++)); do
{
sleep 1; echo 1>>aa && echo "done!"
}&
done
wait
cat aa|wc -l
rm aa
后台执行符号& : 这个实例实际上就在上面基础上多加了一个后台执行 & 符号,此时应该是 15 个循环任务并发执行,最后需要 1S 左右时间。
$ time bash test1.sh
done!
done!
done!
done!
done!
done!
done!
done!
done!
done!
done!
done!
done!
done!
done!
15
real 0m1.017s
user 0m0.035s
sys 0m0.037s
这里需要说明一下 wait 的作用。wait 是等待前面的后台任务全部完成才往下执行,否则程序本身是不会等待的,这样对后面依赖前面任务结果的命令来说就可能出错。例如上面 wc -l 的命令就报错:不存在 aa 这个文件。
好啦,你对程序的并发执行是否有了深刻印象,shell 程序也是批处理程序,对批处理程序也有了初步认识。
4.请写实验报告,
包括你
- 对 shell 的认识,
- 对多进程并发执行的认识,
- 对后台执行的认识,
- 对分时系统的认识,
- 对批处理的认识,
- 对执行时间、系统态时间和用户态时间的认识等等,
画思维导图并配以文字更好,充分展示你的全方位思维。
以下为西邮大二学生实验报告分享:
|