从0开始学习Linux——Shell编程详解【01】

时间:2024-11-19 18:58:01

期目录:

从0开始学习Linux——简介&安装

从0开始学习Linux——搭建属于自己的Linux虚拟机

从0开始学习Linux——文本编辑器

从0开始学习Linux——Yum工具

从0开始学习Linux——远程连接工具

从0开始学习Linux——文件目录

从0开始学习Linux——网络配置

从0开始学习Linux——防火墙配置

从0开始学习Linux——系统服务管理

从0开始学习Linxu——系统常用命令

从0开始学习Linux——进程管理

从0开始学习Linux——用户管理

从0开始学习Linux——文件管理

 上期教程我们学习了文件管理,这期教程我们来学习Shell编程。

一、Shell&Shell编程&Shell脚本概述

1.1 Shell

Shell 是一种命令行界面(CLI),为用户提供与操作系统内核交互的方式,它是用户与操作系统交互的主要手段。它接受用户输入的命令并将其传递给操作系统内核执行,最终返回结果。

Linux中常用的 Shell 程序是 Bash(Bourne Again SHell),它是类 Unix 系统中最常见、功能最强大的 Shell 之一。Bash 是基于原始的 Bourne Shell(sh)开发的,并增加了许多功能,如命令自动补全、命令历史记录、文件名通配符等。

对于Shell我们可以这样去理解:Shell 提供了一个环境,用户可以输入命令,操作系统会执行这些命令,并将结果显示给用户,例如我们前面执行的Shell命令“yum install vim”可以实现下载vim安装包。

补充:常见的Shell

Shell 优势 特点 适用人群
Bash 最常用,功能全面,兼容性强 强大的脚本功能,支持历史、自动完成、命令补全等 大部分Linux和macOS用户
sh 基础且简洁,兼容性好 早期Unix系统的标准Shell,基础的脚本能力 需要跨平台兼容性或简洁性的场合
zsh 丰富的功能和扩展,适合定制和个性化 支持主题、插件、自动补全、增强的命令行编辑等 高级用户和开发人员
fish 用户友好,智能自动补全,视觉效果好 现代化Shell,简洁直观,语法高亮等 需要简便易用的命令行体验的用户

1. Bash(Bourne Again Shell)

Bash是目前最常用的Shell,广泛应用于Linux系统以及macOS(直到macOS Catalina)。它是Bourne Shell(sh)的改进版本,因此得名“Bourne Again Shell”。Bash既继承了sh的基本功能,又增加了许多现代的特性,成为Unix-like系统中的标准Shell。

主要特点:

  • 兼容性:Bash保留了sh的兼容性,因此可以运行sh脚本。它也支持一些较新的编程特性,使得编写Shell脚本更加方便和强大。
  • 命令行编辑:支持通过上下键浏览历史命令,和Ctrl+R进行反向搜索历史命令等功能。
  • Tab 自动完成:通过按Tab键,用户可以快速补全命令、文件名等,极大地提高了操作效率。
  • 内建命令:Bash支持很多内建命令(如echo、read、test、cd等),并且有非常强大的脚本编写能力。
  • 变量和数组:Bash支持变量、数组的使用,并且能够在脚本中进行复杂的计算、流程控制等。

应用场景:

  • 常用在Linux和macOS的命令行界面(CLI)。
  • 被大多数Linux发行版(如Ubuntu、Debian、CentOS等)作为默认的Shell。
  • 用于编写Shell脚本,自动化任务等。

2、sh(Bourne Shell)

sh(Bourne Shell)是Unix系统中的第一种Shell,由Steven Bourne于1977年开发。它为后来的所有Shell(如Bash、ksh等)提供了基础框架。sh是最早期Unix系统的默认Shell,许多现代Shell都在其基础上进行了扩展和增强。

主要特点:

  • 简洁和基础:sh的设计注重简洁和高效,支持基本的命令执行、文件操作和程序控制等功能。
  • 脚本兼容性:尽管sh功能相对较为基础,但它的脚本语言非常强大,支持流程控制、变量赋值、条件判断、循环等基本编程功能。
  • 广泛兼容性:sh是Unix标准Shell,大多数Unix和类Unix系统都至少提供sh的基本实现。

应用场景:

  • 许多Unix系统(如Linux、Solaris、AIX等)的默认Shell。
  • 用于系统初始化脚本,或在无法使用其他更现代Shell的环境中使用。
  • 许多跨平台的Shell脚本采用sh语法,以保证其兼容性和可移植性。

3、zsh(Z Shell)

zsh(Z Shell)是一种功能强大的Shell,最初由Paul Falstad于1990年开发。它是对Bash和其他Shell(如csh、tcsh)进行扩展和增强的产物,提供了更多现代化和用户友好的功能。

主要特点:

  • 自动补全:zsh支持更智能和更强大的自动补全功能,能够自动补全命令、文件名、选项等,并且具有更高的自定义性。
  • 更强的通配符支持:zsh支持更复杂的通配符模式,使得文件匹配变得更加灵活和强大。
  • 主题和插件支持:zsh支持通过框架(如Oh-My-Zsh)安装插件和主题,提供了丰富的扩展,用户可以轻松定制Shell环境。
  • 增强的命令行编辑功能:zsh的命令行编辑功能非常强大,支持诸如文本替换、搜索替换等功能。
  • 高效的历史管理:zsh提供了更为高效和灵活的历史记录管理,用户可以更轻松地查看和重新执行历史命令。

应用场景:

  • 用于开发人员和高级用户,特别是那些喜欢自定义和增强Shell功能的人。
  • 因为其强大的插件系统,zsh广泛应用于开发环境中,特别是在macOS上。
  • 很多开发者使用zsh搭配Oh-My-Zsh框架进行个性化定制。

4、fish(Friendly Interactive Shell)

fish(Friendly Interactive Shell)是一款着重于用户友好和交互体验的Shell。它的目标是为用户提供更加直观和愉悦的命令行体验。fish不像Bash、sh或zsh那样完全遵循POSIX标准,它采用了自己的语法和设计,注重易用性和视觉效果。

主要特点:

  • 语法高亮:fish在命令输入时会进行实时的语法高亮显示,帮助用户清晰地识别命令中的关键字、路径、选项等部分。
  • 智能自动完成:fish提供了智能的自动完成,可以基于上下文进行补全,并且支持命令的参数补全、文件路径补全等。
  • 无需配置的默认设置:fish提供了开箱即用的体验,用户无需进行复杂的配置,自动获得较为直观的功能,如命令高亮、提示等。
  • 现代化特性:fish支持现代Shell的诸多特性,如用户友好的变量定义、函数定义和流程控制等,但不完全兼容Bash和sh的语法。
  • Web配置界面:fish提供了一个基于Web的配置界面,用户可以通过浏览器直接调整Shell的设置和外观。

应用场景:

  • 适合那些希望快速上手并享受流畅命令行体验的用户,尤其是那些对Shell不熟悉但想提高生产力的开发者。
  • fish的语法和功能虽然与Bash有所不同,但其出色的交互式体验,使它成为许多开发者和技术爱好者的选择。

1.2 Shell编程

1.2.1 概述

Shell 编程 是指使用 Shell 提供的命令和功能进行脚本编程。Shell 编程通常用于自动化任务、系统管理、批处理等场景。Shell 脚本是一系列Shell命令的集合,通常保存为一个文本文件,并可以通过运行该脚本来执行这些命令。

Shell 编程的特点包括:

  • 主要使用 Shell 的命令和语法(如if语句、for循环、变量、函数等)来编写脚本。
  • 可以进行文件操作、进程控制、条件判断、循环控制等。
  • 用于自动化日常管理任务(如备份、监控、日志处理等)。

注意:

我们需要知道Shell 编程(或称为 Shell 脚本编程)通常被认为是一种 脚本语言,而不是传统意义上的编程语言。它用于操作和自动化操作系统(尤其是类 Unix 系统,如 Linux 和 macOS)的命令行界面。具体来说,Shell 脚本是通过 Shell 程序(如 Bash、Zsh、Fish、Ksh 等)解释和执行的一系列命令和控制结构。

换句话说Shell 编程语言(如 Bash)属于 脚本语言,更倾向于自动化和命令行任务的编写。它不是一种通用的编程语言(如 Python 或 C),但在操作系统管理和脚本化任务中具有重要地位。

1.2.2 Shell和Shell编程关系

  • Shell 是运行环境:Shell 提供了一个命令解释和执行的环境,用户可以在其中输入命令,操作系统会执行这些命令。Shell 本身就是一个命令行解释器,它将用户输入的命令翻译成操作系统可以理解和执行的系统调用。

  • Shell 编程是命令的组合与自动化:Shell 编程则是在这个环境中,利用 Shell 提供的语法和功能来编写脚本。Shell 编程就是把多个命令组合在一起,进行更复杂的操作,比如条件判断、循环、函数定义等。

我们可以把 Shell 看作是一个交互式工具,而 Shell 编程则是在这个工具的基础上,通过脚本的方式来自动化处理任务,减少手动操作。

1.2.3 Shell编程用途

系统管理与自动化运维

  • 自动化部署:Shell 脚本能够帮助开发人员和运维人员自动化服务器和应用程序的部署过程。例如,可以写一个脚本来更新系统、安装所需的软件包、配置服务器等。
  • 定时任务管理:通过cron配合 Shell 脚本,可以安排周期性任务的自动执行,比如定时备份文件、清理日志文件、监控磁盘空间等。
  • 日志分析与处理:运维人员可以用 Shell 脚本分析系统日志、查找错误或异常,并生成报表。常用的工具包括grep、awk、sed等。
  • 文件和目录管理:自动化文件处理,如批量重命名文件、移动文件、清理临时文件等。

开发中的自动化任务

  • 编译与构建系统:在软件开发中,Shell 脚本经常用于自动化构建过程,执行编译命令,打包软件,甚至上传到远程服务器。常见的构建工具如make、gradle等可能会调用 Shell 脚本来实现部分步骤。
  • 代码检查和格式化:开发过程中,Shell 脚本可以帮助进行代码风格检查、格式化等工作,比如自动运行lint工具,检测代码中的潜在错误。
  • 自动化测试:开发人员可以使用 Shell 脚本自动执行测试,运行单元测试、集成测试,并生成测试报告。

批处理与文件处理

  • 批量文件重命名和移动:Shell 脚本可以轻松实现对大量文件的批量操作,如批量重命名文件、转换文件格式、压缩文件等。
  • 文本处理和格式化:Shell 提供强大的文本处理功能,像awk、sed、cut、greep等工具可以处理各种格式的文本文件,进行提取、修改、格式化等操作。

网络与服务管理

  • 自动化网络诊断:Shell 脚本可以用来自动化网络检查和诊断,像ping、tracerout、netstart 等命令可以组合在一起用于监控和排查网络问题。

  • 远程管理:通过 SSH,Shell 脚本可以远程连接到其他服务器并执行命令或进行管理操作。例如,远程备份、文件同步等。

  • 自动化部署与配置:Shell 脚本常常用于自动化配置文件的部署,特别是在多台服务器上进行一致性配置时非常有用。

数据备份与恢复

  • 备份脚本:Shell 脚本可以用来定期备份重要的数据和配置文件,确保数据的安全性。通过与rsync、tar等工具结合使用,可以实现高效的增量备份。
  • 恢复操作:不仅能进行备份,Shell 脚本还可以帮助用户快速恢复备份数据,保证系统的高可用性。

监控与报警

  • 系统资源监控:Shell 脚本可以用于监控系统的 CPU、内存、磁盘使用情况等资源,及时发出警报。可以通过结合top、vmstat、df等命令进行监控。
  • 自定义报警机制:如果监控到资源使用过高或系统出现异常,Shell 脚本可以自动发送邮件或短信通知管理员。

数据库管理

  • 数据库备份与恢复:Shell 脚本经常用于自动化数据库的备份与恢复过程。例如,MySQL 数据库可以使用mysqldump命令进行备份,Shell 脚本则可定时执行这些备份操作。
  • 数据库维护:可以通过 Shell 脚本自动执行数据库清理、优化、索引更新等任务。

安全与权限管理

  • 用户管理:Shell 脚本可以用来自动化用户的创建、修改、删除等操作,方便批量处理。
  • 权限管理:可以使用 Shell 脚本批量设置文件和目录的权限、修改文件所有者等操作,以确保系统安全性。

1.3 Shell脚本

Shell脚本是Shell编程的一种实现形式,它是一个包含多个Shell命令的文本文件。Shell脚本文件通常具有.sh扩展名,文件中的每一行可以包含Shell命令或控制结构。脚本文件通常可以直接在Shell环境中运行,用来自动执行一系列命令。

Shell脚本文件通常包括以下内容:

  • 命令:Shell命令(如ls、cp、mv等)。
  • 控制结构:条件判断、循环等(如if、for、while)。
  • 变量:用户定义的变量,用于存储值(如文件路径、输入等)。
  • 函数:为了代码重用,可以定义函数。

通常 Shell 脚本使用.sh扩展名,但这不是强制要求。你可以为脚本文件选择任何名称,只要它是可执行的。

如果我们想要去执行一个shell脚本,直接在命令行里面输入shell脚本文件即可,例如我们要执行opt目录下的mysql_server.sh脚本,那么我们可以直接在命令行输入/opt/mysql_server.sh,但是这种方式就要要求用户对该脚本文件有执行权限(对于权限的赋予详情见前期文件管理教程)。

若我们不想去改变脚本文件的权限,或者我们没有执行权限,那么我们可以使用bash或者sh等命令去执行,例如还是要去执行上述的mysql_server.sh,但是我们并没有执行权限且也不想去修改文件权限,那么我们可以使用bash或者sh的方式:bash /opt/mysql_server.sh。

二、Shell编程入门

这里我们先来完成“hello world”文本输出案例。

2.1 Shell脚本借本结构

在此之前我们先来了解一下Shell脚本基本结构。

一个 Shell 脚本通常包括以下结构:

Shebang(解释器声明):每个脚本的开头都应该指定一个解释器,告诉系统该使用哪个程序来执行这个脚本,例如bash环境就是“#!/bin/bash”。

#!/bin/bash

注释:注释是通过#开始的,#后面的内容将被忽略,用于解释代码的功能或提供额外的信息。

命令执行:脚本中的每个命令会按顺序执行。例如,echo命令用于输出文本。

echo "hello world"

2.2 hello world案例

我们在了解了Shell脚本借本结构以后,就可以开始Shell编程入门的第一个案例:输出文本“hello world”。

首先我们需要现在我们的Centos7系统里面找一个位置,然后创建一个hello.sh。

那么我们一般会把sh脚本放在哪个位置呢?

1、用户主目录

用户自己编写的Shell脚本通常保存在用户的主目录中。这个目录通常是/home/用户名,例如 /home/tom。在这个目录下,我们可以创建一个名为scripts或类似名称的子目录来存放脚本文件,例如/home/tom/scripts。

在主目录下存放脚本的好处是:每个用户都可以有自己的脚本,且不会影响系统的其他部分。

2、系统目录

如果脚本是系统级的,需要全体用户都可以访问和执行,可以将Shell脚本放置在以下目录之一:

  • /usr/local/bin/:这是一个常见的目录,用来存放自定义的、由管理员安装的可执行脚本。这里的脚本可以被系统中的所有用户执行。

  • /usr/bin/:这个目录一般用来存放系统范围内的可执行程序和脚本。通常这里的脚本是系统或软件包的一部分,不建议直接存放用户自定义的脚本。

  • /opt/:如果脚本是某个特定软件包或应用的一部分,也可以放在这个目录下,例如:/opt/my_sh/scripts。

3、/etc/目录

一些用于系统初始化、配置或管理的Shell脚本可能会存放在/etc/目录下,特别是当它们用于启动时自动执行或者与系统服务相关时。例如/etc/init.d/(传统的 SysV 脚本)或/etc/systemd/(systemd 服务相关的脚本)。

这些脚本一般由管理员或系统管理员创建和维护。

4、临时目录

有些临时使用的Shell脚本可以放在/tmp/目录中,但这只是临时存储,且/tmp/目录中的内容会在系统重启后清空。因此,不建议把长期使用的脚本放在这里。

这里假设我们将hello.sh脚本创建在/root/目录(root用户的家目录)下。

vim /root/hello.sh

创建好以后就在该脚本文件里面编写代码

#!/bin/bash


echo "Hello, world"

 现在我们的第一个案例就已经成功了。

三、变量

变量是脚本中非常重要的一部分。Shell 变量用于存储值,可以是数字、字符串或其他类型的数据。这些值可以在脚本中被引用、修改或用于控制程序的流程。

3.1 变量的定义

变量名=值

我们在定义变量的时候需要注意:

  • 变量名可以包含字母(a~z,A~Z)、数字,以及下划线(_)。但变量名不能以数字开头,必须以字母或下划线开头。
  • 变量名是区分大小写的。例如,var和VAR是两个不同的变量。
  • 在定义变量时,变量名与赋值之间不能有空格。赋值的语法格式是变量名=值。
  • 避免使用系统变量名和环境变量名,在shell中一些系统环境变量和特殊变量具有特殊意义。避免使用与这些名称冲突的变量名,以避免意外覆盖和潜在的错误。
  • 避免使用保留字和关键字,shell中存在一些保留字和关键字(例如:while、if等),这些不能用作变量名。虽然在shell中,一些保留字可以作为变量名,但这样做可能会导致歧义,因此不建议使用这些名字。
  • 我们在给变量命名的时候若需要多个单词进行组合,那么推荐使用下划线对单词进行分隔,例如:student_name,并且系统和环境变量最好所有字母大写,普通变量就字母小写然后单词与单词之间下划线进行连接。
  • 我们在给变量命名的时候也需要确保尽量使用英文单词,要见名知意。

当然shell中有一些特殊变量,例如\$0,\$1,$?等。为了避免混淆,应避免使用与这些特殊变量名称相同的名称。

  • \$0:脚本的名称。
  • \$1,\$2,...:脚本接收到的命令行参数。
  • $?:上一个命令的退出状态。
  • $#:脚本参数的个数。
  • $@ 或 $*:所有传递给脚本的参数。

例如我们在sh脚本中定义变量用于存储学生姓名。

student_name="张三"

3.2 变量的引用

3.2.1 基本使用

引用变量就是获取变量中存储的值。Shell中,引用变量的方式是通过在变量名前加上$符号。例如,要引用变量stuent_name的值,就使用$student_name。

上图中的代码我们去打印student_name的值发现输出的是student_name,下面我们加上$符号去完成代码的改造。 

 那么我们继续思考,假设我们再定义一个变量name1,然后将student_name的值交给name1我们该如何操作呢?

 上图中我们直接将student_name赋值给name1,结果打印的结果确实student_name,下面我们加上$符号再试一次。

 当然我们也可以在sh脚本中的字符串里面使用变量引用。

但是,在单引号和双引号的字符串中引用变量却存在着不同:

  • 双引号:在双引号内引用变量时,Shell会对其中的变量进行扩展,将其替换为对应的值。
  • 单引号:单引号内的任何内容都被当作普通字符串,不会进行变量扩展。

 3.2.2 "{}"使用

假设现在我们定义一个变量name1且取值为”王五“,然后想要输出”你好,王五233“。

我们可以发现脚本并没有达到我们的预期,这是因为name1后面加上了233字符,导致变量名成了name1233,这个变量是不存在的,那么想要达到我们的预期效果,我们需要想办法将name1和233进行分隔开。

在Shell中大括号用来明确变量的边界,尤其在引用变量时,避免变量与后面的字符混淆。在变量名和紧跟着的字符之间使用大括号,可以让Shell清楚地识别变量的结束位置。

下面我们来改进代码。

 3.2.3 命令替换

Shell允许使用命令的输出作为变量的值,称为命令替换。命令替换使用$(其它输出命令)的语法。

上述代码中date命令输出的日期值传递给了current_time。 

3.3 局部变量&全局变量

Shell中变量可以被分为 局部变量 和 全局变量,它们的作用域和生命周期有所不同。

 3.3.1 全局变量

全局变量是在 Shell 脚本或交互式 Shell 环境中定义的,可以在脚本的任何位置访问和修改。全局变量的作用范围从定义的位置开始,到脚本的末尾,或者在交互式 Shell 会话结束为止。

上述代码中的name1就是一个全局变量,它的作用域是整个脚本,也就是在脚本运行期间一直有效,直到脚本结束,或者终端关闭。

3.3.2 局部变量

局部变量是在函数内部定义的变量,它的作用域仅限于该函数内部。在函数外部,局部变量是不可访问的。局部变量一旦定义,它在函数调用结束后会被销毁,不会影响到外部的变量。

局部变量仅在其所在的函数或代码块中有效,一旦函数调用结束,局部变量会被销毁。

 3.4 特殊变量

Shell中有一些特殊的内置变量用于存储脚本的状态信息或命令行参数,常见的有:

  •  $$:当前Shell进程的PID(进程ID)。
  • $#:传递给脚本或函数的参数数量。
  • $?:上一个命令的退出状态(返回值)。
  • $@:传递给脚本或函数的所有参数。

3.5 变量的扩展与替换

Shell提供了多种变量扩展和替换方式,帮助你更加灵活地操作变量:

  • ${变量名#pattern}:从变量值的开始部分删除最短匹配的模式。
  • ${变量名##pattern}:从变量值的开始部分删除最长匹配的模式。
  • ${变量名%pattern}:从变量值的末尾删除最短匹配的模式。
  • ${变量名%%pattern}:从变量值的末尾删除最长匹配的模式。

 3.6 环境变量&系统变量

Shell中有许多内置环境变量,它们提供了关于系统和用户会话的信息。例如:

  • $HOME:当前用户的家目录。
  • $USER:当前用户的用户名。
  • $PWD:当前工作目录。
  • $PATH:存储可执行文件路径的环境变量。

 四、常量

在 Shell 中,常量 是指在程序运行过程中不会改变的值。

通常,Shell 没有内建的常量机制,但我们可以通过其它方式实现常量的效果。

注意:常量在命令的时候建议所有字母都大写。

4.1 readonly命令

readonly命令可以将变量标记为常量,一旦赋值后,该变量的值就不能再被修改。

 4.2 declare -r命令

对于declare命令将在后续教程中详细解释。

本节教程就先到这里,更多内容将在后续教程中进行讲解。