嵌入式 Linux 入门(五、Shell 脚本编程上:认识 Shell 脚本)
前言
虽然对于做嵌入式 Linux 来说,Shell 脚本使用相对来说不需要那么深入,一般使用的脚本也不会太复杂,但是我们也经常需要用到,所以还是需要特别学习一下。
何为脚本?脚本有很多名字,比如可称为自动化程序,它的目的都是减少人工操作,提高效率,脚本语言是像剧本一样教计算机办某个事情的语言。
我们在前面的文章中已经学习过 Linux Shell ,我们知道 Shell 既是一种命令语言,又是一种程序设计语言,本文我们就来认识学习一种为 Shell 编写的脚本程序,Shell 脚本(shell script)。
博主当初在学习 Shell 脚本的时候,其实也是有点坎坷,最主要的是当时的心态问题,心中认为嵌入式开发 Shell 脚本会简单的就好,但是因为有这种心态,导致学习的时候不是那么用心,以至于入门就花了好长一段时间,所以学习还是得摆正心态,用心!
嵌入式 Linux 入门系列博文:
嵌入式 Linux 入门(一、Linux 基本介绍及文件结构)
https://xie.infoq.cn/article/1adbc03be480d8203f8b1ed4a
嵌入式 Linux 入门(二、Linux 文件系统、文件类型及权限管理)
https://xie.infoq.cn/article/4d2e926fda47f2eff019ae0e4
嵌入式 Linux 入门(三、Linux Shell 及常用命令说明)
https://xie.infoq.cn/article/b25c452df449abc1806ba446a
嵌入式 Linux 入门(四、Linux 下的编辑器 — 让人爱恨交加的 vi )
一、Shell 脚本基础说明
所谓脚本,就是一个文件,文件里面存放的是 特定格式的指令,系统可以 使用脚本解析器翻译指令并执行 。
在我们熟悉的 Windows 中,我们会有 bat 文件,这可以认为是 Windows 中的脚本,通过代码来实现一系列的任务。
比如在以前学习 STM32 的时候正点原子源码中的工程清理脚本:
1.1 什么是 Shell 脚本
在 linux 中,我们所说的 Shell 脚本: 由 Shell 命令 以及 相关的语法语句 组合组成的一个文件。
Shell 脚本通过解释器解释运行,不用编译即。
上面说的 Shell 命令,就是我们在前面文章 《嵌入式 Linux 入门(三、Linux Shell 及常用命令说明)》 学习过的 Shell 命令。
上面说的 相关的语法语句,就是我们本文需要学习的 Shell 脚本的语法。在 Shell 脚本中,也有变量,流程控制语句等,他们和 Shell 命令结合起来就形成了一个功能强大的 shell 脚本。
Shell 脚本是一个文件,由 Shell 命令 和 相关语法语句 组成!
1.2 Shell 脚本的意义
我们开头就说过,脚本的目的都是减少人工操作,提高效率。
Shell 脚本的意义简单概括为以下几点:
1. 重复步骤的执行;
2. 批量事物的处理;
3. 定时任务执行;
4、方便管理员进行文件管理,Linux 下一切接文件,所以可以理解为方便管理员进行所有东西的管理,包括安装,部署,启动,备份,监控,分析等等功能 。
在我们开发 STM32 的时候,也可以使用 GCC 环境,那么就有一个 Makefile 文件,Makefile 就是一种类似于 Shell 脚本的 “脚本” (Makefile 与 Shell 脚本语法有不同)。
使用 Makefile 我们可以简单的使用一个 make 命令经常程序的编译工作,大大提高了我们的开发效率。(Makefile 的内容,我们在后面也会有文章说明)。
1.3 Shell 命令的本质
本小结是为了让我们加深对 Shell 命令的理解。
首先要说明几个概念 :Shell 的 内置命令 与 外部命令 。
Shell 内置命令
Shell 内置命令是内嵌在 shell 中的,是 shell 的一部分,这些命令由 shell 程序识别并在 shell 程序内部完成运行,当系统加载 shell 时被加载并驻留在内存中。
比如 linux 的一些简单命令 cd,pwd 等。
Shell 外部命令
外部命令其实是 linux 的 程序,其命令执行过程是由 shell 程序控制的,在需要时才将其调用内存,当一个外部命令被执行时,一个新的进程即被创建同时命令被执行,外部命令是对应着一个程序,可以理解为 Shell 调用了其他程序的运行。
shell 程序管理外部命令执行的路径查找、加载存放,并控制命令的执行。注意,程序功能强大程序量也会很大。
外部命令是在 bash 之外额外安装的,通常放/bin,/usr/bin,/sbin,/usr/sbin 文件夹中。
判断内部命令还是外部命令:
我们可以使用 type
命令判断命令是内置还是外部的,如下图:
☆ 那么问题就来了 ,一个程序是如何成为一个 Shell 命令的呢?☆
直接简单点说明:
当一个命令被敲下, Shell 首先回到内存中去寻找它的内置命令,当遍历所有内置命令没有找到的时候,它会去设置好的 环境变量 中寻找外部命令,其实就是寻找所对应的应用程序,如果找到对应的应用程序,它会创建一个新的进程,然后在进程里面执行这个应用程序。 如果内外命令都没有找到,就会报错。
在上面的句子中,外部命令是在设置的环境变量中查找的,那么如何查看环境变量呢?
我们可以使用echo
命令 直接打印环境变量,使用语句echo $PATH
,如下图:
一个有趣的测试
我们上面知道了 Shell 外部命令是通过设置好的环境变量(就是一些目录)中的一些应用程序。
所以我们是不是可以自己做一个 Shell 命令呢?
我们使用 vi 编辑器写一个简单的 hello world 程序,如下图:
完成上面步骤我们看到, hello 现在可以运行,可以认为是一个应用程序,结果是输出 hello,world!
重点来了,首先我们这里要运行,是需要用 “.” 指定为当前路径,./hello
表示当前路径下的 hello 程序,我们也只能在这个路径中运行 hello 程序。
但是 Shell 命令,不受路径的约束,我们想要把 hello 这个程序变成 Shell 命令,我们尝试把 hello 放到环境变量的路径中去。
如上图,我们把一个 c 语言的 hello 程序变成了一个 shell 命令。
通过上面的测试,详细大家应该更加理解 Shell 命令的本质。
1.4 Shell 脚本解释器
Shell 脚本解释器?本小结就是说明一下,shell 脚本解释器的种类。
在我们前面讲解 Shell 命令的文章中介绍 Shell 的时候有说过: Shell 有很多种实现,我们最常用为 bash。
我们再复习说明一下 Shell,Shell 介于操作系统内核与用户之间,负责接收用户输入的操作指令并进行解释,将需要执行的操作传递给内核执行,最后输出执行结果, Shell 是一个 命令解释器 。
综上我们可以总结出, 在 Linux 下面有多种命令解释器,bash (Bourne Again Shell)是我们最常用的命令解释器。
原因好像是因为 bash 易用以及免费,使用不同的 Shell 时,其内部指令、命令行提示符等方面会存在一些区别。
我们在 《嵌入式 Linux 入门(二、Linux 文件系统、文件类型及权限管理)》 中说明用户的时候,已经知道了用户使用的是哪种 Shell ,但是我们有更加直接的方式,直接使用命令echo $SHELL
:
我们说系统中的 Shell 有很多种,那么到底有哪些呢?
在我们使用的 Ubuntu 中,可以通过查看 /etc/shells 文件了解当前系统下所有支持的 shell,如下图:
本文脚本编程,是针对于我们最常用的 bash 来说明的。
1.5 编译型语言 和 解释型语言
简单说明一下 编译型语言 和解释型语言,区别一下我们熟悉的 C 语言 于本文学习的 Shell 脚本语言。
本小结参考文章:编译型语言和解释型语言的区别
编译型语言
编译型语言要求必须提前将所有源代码一次性转换成二进制指令,也就是生成一个可执行程序(Windows 下的 .exe),比如 C 语言、C++、Golang、Pascal(Delphi)、汇编等
使用的转换工具称为编译器
对于编译型语言,开发完成以后需要将所有的源代码都转换成可执行程序,只要我们拥有可执行程序,就不再需要源代码和编译器了,可以随时运行。
编译型语言可以脱离开发环境运行。
编译型语言一般是不能跨平台的。
首先,可执行程序不能跨平台,pc 端的程序不能在 arm 芯片上运行,windows 下的程序不能在 linux 上运行;
其次,源代码不能跨平台,这个有些是可以跨平台,有些是不可以。
解释型语言
解释型语言可以一边执行一边转换,需要哪些源代码就转换哪些源代码,不会生成可执行程序,比如 Python、JavaScript、PHP、Shell、MATLAB 等
使用的转换工具称为解释器。
对于解释型语言,每次执行程序都需要一边转换一边执行,用到哪些源代码就将哪些源代码转换成机器码,用不到的不进行任何处理。每次执行程序时可能使用不同的功能,这个时候需要转换的源代码也不一样。
因为每次执行程序都需要重新转换源代码,所以解释型语言的执行效率天生就低于编译型语言,甚至存在数量级的差距。计算机的一些底层功能,或者关键算法,一般都使用 C/C++ 实现,只有在应用层面(比如网站开发、批处理、小工具等)才会使用解释型语言。
在运行解释型语言的时候,我们始终都需要源代码和解释器,所以说它无法脱离开发环境。
相比于编译型语言,解释型语言几乎都能跨平台。
这里要注意一下,解释型语言的跨平台,是指源代码跨平台,而不是解释器跨平台。
解释器用来将源代码转换成机器码,它就是一个可执行程序,是绝对不能跨平台的。
官方需要针对不同的平台开发不同的解释器,同样的代码在不同平台的执行结果才是相同的。在不同的平台下,解释器会将相同的源代码转换成不同的机器码,解释器帮助我们屏蔽了不同平台之间的差异。
对于编译型语言,只需要提供可执行文件就可以运行,源代码可以不提供,所以编译型语言的可以不开源。
对于解释型语言,需要所有的源代码才能运行,所以解释型语言的程序一般是开源的。
额外提一句,最近几年很火的 Python 属于典型的解释型语言,运行 Python 程序需要解释器的支持,只要你在不同的平台安装了不同的解释器,你的代码就可以随时运行,不用担心任何兼容性问题,也就是说,Python 的可移植性是很强的。
我们开发 STM32 使用的 C 语言 是编译型语言,本文说明的 Shell 脚本语言是 解释型语言。
通过上面的介绍,让我们更好的理解了上一小节说的 Shell 脚本解释器为什么有不同种类,同时也能让我们对编程语言能够一个新的认识或者理解。
二、第一个 shell 脚本
2.1 写一个 Shell 脚本
讲了这么多,我们来写第一个 Shell 脚本,使用 vi 编辑器创建一个脚本文件:
扩展名并不影响脚本执行,脚本后缀名可以任意修改,仍然可以正常运行。只不过我们写脚本的时候一般都需要见名知意,所以对给对于的后缀名: shell 脚本后缀为 .sh,Python 后缀名为 .py 。
2.2 Shell 脚本的启动方式
在上面我们写完了一个 Shell 脚本,我们尝试用以往的程序启动命令 "./" 运行试试:
发现无法运行,那么 Shell 脚本到底是如何启动的呢?
当程序运行
首先我们先说我们熟悉的方式,就是上面这种方式,当做程序运行,但是上面实际上是失败了,这是为什么呢?
我们看一下文件属性,如下图,新创建的 hello.sh 脚本并没有执行权限:
那么我们就给他执行权限,在以前我们讲解过,给一个文件权限是用 chmod 命令,我们还说过可以使用chmod 777
直接给一个文件最大权限,今天我们说另外一种方式使用 chmod +x
添加执行权限 ,如下图:
添加了执行权限以后,我们就可以把脚本当成一个程序一样执行,如下图:
指定解释器运行
在上文我们介绍过,Linux 中也有很多种 Shell 解释器,我们可以直接使用解释器来运行 Shell 脚本,如下图:
直接指定解释器执行不需要为脚本赋予执行权限,有和没有权限都可以。
当然,除了 bash 我们使用其他的解释器也是可以的,如下图:
source 和 .
直接使用命令source
和 .
执行 Shell 脚本,此种方式也不需要执行权限,如下图:
那么初学者会疑问,source
和 .
是什么?
当你不知道是什么的时候,不妨根据文章前面提到的判断内建命令还是外部命令的方式尝试一下!如下图:
测试过后,我们知道了, source
和 .
是 shell 的内置命令,那么是命令就好说了,记住就行了。
source
是一个 linux 命令,通常使用 .
来代替,使用方式如下:
额外说明一下:前两种方式:当成程序运行和指定解释器运行 shell 脚本时都是在当前 shell 环境下又开了一个子 shell 环境,当脚本执行完后,子 shell 环境立刻就会关闭。而使用source
命令是在当前 shell 环境下执行的。
结语
本来是想一篇文章把 Shell 脚本说完,但是作为入门文章,在基础知识的说明上写了很多的东西,其中也不乏有一些需要理解测试的内容,所以还是把 Shell 脚本编程分成两篇文章。
此篇主要在于基础的介绍说明,下一篇文章主要介绍 Shell 脚本的语法。
本文虽然只是理论的介绍说明,但是不乏有很多值得品味的小细节,对于入门者来说看完以后值得好好的想一想,试一试,希望大家都能有所收获!
本文先到这里,谢谢大家!
版权声明: 本文为 InfoQ 作者【矜辰所致】的原创文章。
原文链接:【http://xie.infoq.cn/article/16e4569fa32dce00a39eaddaf】。文章转载请联系作者。
评论