# 讲讲Linux、Bash、Shell脚本 当今时代,技术栈和层级越发复杂,各种底层技术已经经过层层封装,变得更加细化和模块化,通过模块化建模,我们就可以将自己的想法,像搭积木一样组合起来。 首先,你有什么需求,你的这个需求可以被什么技术解决,了解它的基本概念,然后把它变成生活的一部分,想方设法用它。遇到问题了怎么办?把大问题拆分成小问题,找搜索引擎解答。 > 重点:了解某项技术的基本概念,基本原理,才是掌握这项技术的基础。 下面我们来学习在Linux系统经常使用的shell脚本吧。本文主要面向linux初学者以及对linux感兴趣的人。请自行准备linux系统,Ubuntu或者centos都可以。 ## 什么是Linux内核? 操作系统是运行在计算机上的重要软件,但它的核心却鲜为人知。Linux内核,如CentOS、Redhat、Ubuntu等操作系统的核心,可以被视为计算机的大脑和心脏,是操作系统不可或缺的一部分。如果没有内核,操作系统将会失去自己的灵魂,你的电脑也将变得毫无生机。 内核的角色是负责管理操作系统的核心功能,就像一个大管家一样。它的小伙伴们则负责处理各种任务,为用户提供更好的使用体验。这个团队精神,让计算机可以高效地管理、分配和控制资源。 ## 什么是shell? 我们都知道,计算机只能理解0和1这两个数字(二进制),就像我们需要翻译才能与外国人沟通一样,与计算机进行交互也需要一个翻译器,这就是shell。但实际上,当我们与计算机交互时,我们是在与内核进行交互,因为我们所看到的内存、磁盘、CPU等都只是内核虚拟出来的概念。无论我们进行什么操作,最终都是由内核真正执行在计算机硬件上的。内核就像一个不可见的掌控者,它负责管理和协调计算机的所有资源,让计算机运行起来。因此,了解内核对于理解计算机的工作原理和进行更深入的技术探究是至关重要的。 **总结下shell定义**: Shell是计算机中的一种特殊程序,它是一个命令语言解释器,可以将用户输入的命令翻译成内核可以理解的指令,再由内核交给CPU执行。作为用户与内核之间的接口程序,Shell在计算机操作中扮演着非常重要的角色。不管是通过图形界面(GUI)还是命令行界面(CLI)进行交互,用户的一切输入都会经过Shell的解释和处理,最终被传递给内核,控制计算机硬件执行相应的操作。因此,Shell的作用不仅仅是简单地执行命令,而是负责管理计算机资源、控制系统进程和协调各种操作,是整个计算机操作系统中不可或缺的一部分。 ## 什么是bash shell? Shell有多个版本,例如sh、bash、csh、ksh等,其中bash是Linux世界最广泛使用的shell,也是许多Linux发行版的默认shell。不同版本的shell功能和特点也有所不同,用户可以根据自己的需求选择合适的版本。 获取当前系统可用的shell版本可以帮助用户了解自己的操作系统,并为使用特定的shell版本提供方便。 ```bash [root@localhost ~]# cat /etc/shells /bin/sh /bin/bash /sbin/nologin /usr/bin/sh /usr/bin/bash /usr/sbin/nologin ``` 查看当前使用的shell ```bash [root@localhost ~]# echo $SHELL /bin/bash ``` ## 什么是CLI和GUI? - CLI:Command Line Interface(命令行接口) - GUI:Graphical User Interface(图形用户接口) - 命令行界面是最原始的界面,通过在终端上输入指令,计算机会给出相应的回应,而图形界面是一种更加友好的界面,可以通过图形化的操作完成任务。 - 无论是命令行界面还是图形界面,都是我们与计算机进行交互的方式。当我们在电影中看到那些黑客的电脑界面时,那是命令行界面,其输出信息让人眼花缭乱;而当我们在Windows系统上使用鼠标点点点时,那是图形界面。当然,Linux也有自己的图形界面,但我们与计算机进行交互的方式都是通过shell进行的。 尝试执行几个基本命令 ```bash [root@localhost ~]# echo "today" today [root@localhost ~]# date Sat Jan 12 23:48:13 CST 2019 ``` ## 什么是标准输入、标准输出和标准错误输出? - 在Linux系统中,一切都被视为文件,甚至包括标准输入、标准输出和标准错误输出。 - 标准输入是指向命令行的默认连接,而标准输出和标准错误输出默认连接到终端屏幕。 - 当我们执行一条shell命令时,实际上就打开了这三个文件,它们可以被看作是三条管道,分别将输入、输出和错误流连接到相应的地方。 - 默认情况下,我们通过键盘输入的内容通过标准输入这条管道流入相应的命令,命令的执行结果会通过标准输出或标准错误输出这条管道流出到屏幕上,呈现在我们面前。 - 管道的概念非常重要,它是Linux系统中的一个核心概念,也是在shell中进行I/O重定向的关键机制。 比如输入`cat test.txt`,cat这个命令作用是从命令行给出的文本中读取数据并将数据送到标准输出。 如果test.txt中有内容,那么标准输入就不是键盘了,而是该文件,文件内容通过“标准输入”这个“管道”流向cat命令,cat命令读取其内容,然后将内容“流出”至标准输出,即屏幕上。 ```bash # 将"hello"添加到test.txt这个文件中,如果不存在就创建 [root@localhost ~]# echo "hello" > test.txt # 输出test.txt文件内容 [root@localhost ~]# cat test.txt hello #标准输出 ``` 假如`test.txt`不存在,那么就会报错,错误信息通过“标准错误输出”这条管道“流出”至屏幕上。 ```bash [root@localhost ~]# cat test.txt cat: test.txt: No such file or directory #标准错误输出 ``` 假如`cat`命令后面没有参数,那么其标准输入便是键盘了,终端就会等待我们输入,`cat`获取标准输入,通过“标准输出”这条管道输出到屏幕上。 ```bash [root@localhost ~]# cat hello # 标准输入 hello # 标准输出 ``` ## 什么是重定向? 在Linux中,每个命令都有标准输入、标准输出和标准错误输出三个文件描述符,它们分别对应着键盘、显示器和显示器。通过重定向符号>、>>和<,我们可以改变这些文件描述符的流向,将输出重定向到一个文件中,或将文件作为输入流,而不是从键盘输入。 在重定向中,>代表覆盖重定向,将输出覆盖到目标文件中;而>>代表追加重定向,将输出添加到目标文件的末尾。通过<符号,我们可以将文件作为命令的标准输入。 在Linux中,每个文件都有一个唯一的文件描述符。标准输入的文件描述符是0,标准输出是1,标准错误输出是2。因此,我们可以通过重定向符号>和2>来将标准输出和标准错误输出分别重定向到不同的文件中。如果想要将标准错误输出和标准输出合并到同一个文件中,可以使用2>&1或&>重定向符号。其中2>&1代表将标准错误输出重定向到标准输出,而&>则代表将标准错误输出和标准输出都重定向到同一个文件中。 ## 什么是管道? 前面我们了解到,命令的标准输出默认是屏幕,假如该命令的标准输出我们想再利用怎么办?那就需要利用管道了。强调一下,标准输出是指命令执行成功后的输出。 举个例子: ```bash [root@localhost ~]# echo “zhangsan” | useradd # 这条命令的意思是输出”zhangsan“,并利用useradd命令添加其为linux普通用户 # ”zhangsan“为管道前的标准输出,管道将其变成后面useradd命令的标准输入 ``` 注意事项: - 管道只能处理前一个命令的标准输出,标准错误输出无法处理 - 管道后面的命令必须能够接受标准输入才行,像`ls`命令就不接受标准输入,所以它不能放在管道后面。`ls`命令的作用是列举目录下的内容,当然了,在linux世界怎么能接受不能呢,利用xargs就可以把管道前的标准输出当作`ls`命令的标准输入了 ```bash [root@localhost ~]# echo "/etc"| xargs ls # 没有xargs的话,这里的ls只能列举当前目录的内容,而非/etc这个目录 ``` ## 什么是shell脚本? Shell是一种命令语言解释器,它是一种程序,通过调用内置或其他基本命令来实现各种功能。与编程语言使用库不同,Shell没有库,它完全依赖于命令。在日常使用中,我们与Shell交互,输入各种命令来实现所需的功能。 然而,当我们需要频繁地执行相同或类似的命令时,手动输入命令将会变得枯燥乏味,而且容易出错。这时,Shell脚本便可以派上用场。Shell脚本是一种文本文件,其中包含一系列Shell命令,它们按顺序执行以实现一定的功能。Shell脚本不仅可以减少重复工作,还可以实现自动化,提高生产效率和质量。 ## shell脚本基本组件 shell脚本是由各种shell命令组成,但绝对不是简单的命令堆积,它像其他编程语言一样,有自己的基本组件。 - shell命令 - shell内部命令,如ls、cd、pwd等 - 其他命令 - who、du、free等各种丰富的功能命令 - 数据结构 - 变量、数组、字典 - 函数 - 将一系列命令组合成一个函数,减少重复工作 - 控制流 - if、case等分支语句 - for、while等循环语句 ## 如何快速编写一个脚本? ### 脚本组成 一个完整的脚本有三部分组成:脚本声明、注释以及可执行语句。 - 脚本声明 - 前面说过,CPU只认识二进制,也就是说只能执行二进制程序文件 - 我们的脚本是文本文件,需要一个解释者解释下,也就是shell,shell本身是二进制程序 - CPU运行shell程序,shell解释脚本的每一行内容,然后找到对应的二进制程序,由CPU执行 - 所以,首先我们得告诉CPU,该脚本用哪个解释器来解释 - 如何声明,在脚本第一行顶格写:#!/bin/bash - `#!`被称为shebang符号,用来声明所使用的解释器,一旦执行某个脚本,CPU看到第一行,就会去执行该解释器,再由解释器去找对应的命令程序 - /bin/bash指明bash二进制程序的位置 - 注释 - 简单的脚本还好,一旦复杂起来,可读性就大大降低,所以注释相当重要 - 解释器会忽略注释 - shell脚本中的单行注释符号是`#` - 至于多行注释,方法有很多,一般用不到的 吧 - 可执行语句 - linux命令以及相应的控制流与数据结构 - 相关语法可以在网上找 - 需要条件判断了,就搜`shell if语法`或`shell case语法` - 需要重复执行某命令,就搜`shell for循环`或`shell while循环` - 某个需求不知道用什么命令,就搜`需求关键字`好了 - 某个命令不知道怎么用,直接在命令行输入`man 命令`或者直接百度 ### 脚本执行 执行脚本主要有三种方法: - 直接运行脚本文件 - 这种方法需要脚本有可执行权限:chmod u+x ping.sh - 然后输入脚本的绝对路径或相对路径来执行文件 - 比如相对路径,你得先进入脚本所在的目录,然后执行:./ping.sh - 利用解释器执行 - bash ping.sh - sh ping.sh - 利用source或. - source ping.sh - . ping.sh 第一种方法,如果你没有shebang语句(即第一行声明解释器),可能会报错;第二种方法,你可以不声明解释器类型,因为你是直接用解释器来执行的,也可以不赋予执行权限;第三种方法,你是在当前shell环境来执行的,前两种实际上都是在子shell中执行,执行完毕才退回到当前shell。 基本上用哪种方法都行,看你心情。 ```bash # 假如你想把执行结果保存到一个文件,也就会利用输出重定向 # 但同时你又想输出其结果到屏幕上,那就会用到tee命令了 [root@localhost ~]# bash ping.sh | tee out.txt 192.168.1.1 is up 192.168.1.2 is down ... #现在你想知道有多少个ip是通的,这就用到涉及文本过滤命令grep以及统计命令wc [root@localhost ~]# grep "up" out.txt | wc -l 3 ``` 最后补充一点,同window不同,linux世界,文件后缀没有任何意义,加后缀名只是方便人类自己查看。