# Linux Shell 编程入门 Day01:Shell 基础认知、脚本编写规范、变量四大类型、数值运算

0 阅读11分钟

一、实验环境准备

本次实验基于模板机创建 1 台虚拟机,完成 IP 配置后,使用 WindTerm 远程连接主机,为后续脚本编写与执行做好环境准备。


二、Shell 环境及核心特性


Linux 层级关系梳理: 程序/用户输入的命令(ls/cd/pwd) ↓ Shell解释器(/bin/bash) ↓ Linux系统内核 ↓ 计算机硬件


1. Shell 是什么

  • Shell 是一门编程语言,也是Linux中解释器的总称,常用于Linux、云计算、运维等服务器领域
    • 解释器:内核与用户之间的“翻译官”
  • 核心作用:用Shell编写的程序文件,可以实现批量自动化执行命令,大幅提升运维效率
    • 脚本:脚本就是功能性文件,又叫程序,运行脚本可以带来相应的功能
  • Linux 默认 Shell 解释器:/bin/bash(最常用、功能最完善)。

2. Shell 两种使用方式

方式特点适用场景
交互式(命令行)手动逐条执行、人工干预、效率低,智能化程度高临时操作、调试命令
非交互式(脚本)批量执行、后台运行、效率高,但需要提前设计、智能化难度大自动化部署、定时任务

3. 常见 Shell 解释器

  • Linux系统所有解释器都被记录在:/etc/shells文件之中(/sbin/nologin也属于是解释器的一种,但不在该文件中)
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
  • 可以使用usermod -s 或者chsh(即change shell,要安装util-linux-user 软件才可以执行)命令 为用户修改默认解释器:
usermod -s /bin/sh tom    # 改为 sh

dnf -y install util-linux-user    #安装软件,提供chsh命令
chsh -s /bin/bash tom     # 改回 bash
  • /bin/bash解释器是默认“最好用的解释器”,也被称之为bash解释器

4. Bash 核心特性

  • 快捷键、Tab键补齐
  • 命令历史
  • 命令别名
  • 重定向
  • 管道操作
  • ......

5. 重定向分类

请添加图片描述

[root@server ~]# head -1 /etc/passwd   >  /opt/ps.txt    #收集正确信息
[root@server ~]# ls  /root /adfas    >    /opt/a.txt     #只收集正确信息 
[root@server ~]# cat    /opt/a.txt                       #查看验证
[root@server ~]# ls  /root /adfas    2>   /opt/b.txt     #只收集错误信息 
[root@server ~]# cat    /opt/b.txt                       #查看验证
[root@server ~]# ls  /root /adfas    &>   /opt/c.txt     #无论正确错误都收集
[root@server ~]# cat    /opt/b.txt                       #查看验证

三、Shell 脚本编写(四步走)

1. 脚本基础认知

  • 脚本:就是一种特殊功能性的文件,提前写好执行的语句,能够完成特定任务
  • 命名规范:通常以 .sh 结尾(如 test.sh)。
  • shell脚本特点:
    • 从上到下、依次执行
    • 批量化处理

(自动化脚本需要避免使用交互式命令)

2. 标准脚本三要素

  1. #!:声明解释器(必须写在第一行)
  2. # 注释:说明作者、功能、步骤
  3. 可执行语句:实际要运行的命令

3. 第一个脚本:Hello World

Shell脚本"四步走": 1.新建脚本文件 2.在脚本中添加可执行的语句 3.赋予脚本文件x执行权限 4.运行脚本

# 1. 创建并编辑脚本
vim /root/first.sh

# 2. 写入内容
#!/bin/bash
# 我的第一个 Shell 脚本
echo "Hello World"

# 3. 添加执行权限
chmod +x /root/first.sh

# 4. 运行脚本
/root/first.sh
# 或 ./first.sh(当前目录下)

4. 脚本两种执行方式

方式 1:需要执行权限(x)
[root@server ~]# /root/first.sh         #绝对路径运行脚本
Hello World
[root@server ~]# ./first.sh             #相对路径运行脚本,前提是要先切换至脚本所在目录
Hello World
方式 2:不需要执行权限
  • 指定解释器运行脚本(默认脚本会使用脚本内声明的解释器程序执行代码)

    • sh 脚本文件:使用sh解释器执行脚本
    • bash 脚本文件:使用bash解释器执行脚本
    • source 脚本文件:使用当前用户的解释器执行脚本
    • . 脚本文件 :使用当前用户的解释器执行脚本,同source一样

注意:运行脚本时指定的解释器优先级要比脚本中指定的解释器优先级要高。 若脚本中指定的是:#!/bin/bash,运行时使用的是:sh 脚本文件 ,那使用的就是sh解释器

[root@server ~]# chmod -x  /root/first.sh    #去掉脚本的x执行权限
[root@server ~]# bash /root/first.sh         #指定bash解释器执行脚本
[root@server ~]# sh /first.sh                #指定sh解释器执行脚本
[root@server ~]# source  /first.sh           #指定使用当前用户的解释器执行脚本
[root@server ~]# .  /first.sh           #指定使用当前用户的解释器执行脚本

重点:source 脚本名 . 脚本名 执行脚本不会新开子进程(可以通过进程树进行观察),其他方式都会开子进程。 (如果指定解释器来运行脚本,会开指定对应解释器的新进程,代码运行在子进程中;如果直接使用绝对/相对路径来运行脚本,会开一个名为这个脚本名的子进程)

当指定解释器时,代码运行在子进程中,会在用户当前解释器中开一个你所指定的解释器子进程,若指定的是sh,则会有: bash--sh--脚本进程

倘若脚本中执行的是cd,exit这类命令,脚本执行完功能后会退出指定的解释器:sh的子进程,所以这时候脚本功能并不会表现出来,并不是因为脚本没有生效。 简单讲,不是脚本没有运行,而是运行后退出了子进程导致看起来脚本没有生效。 (使用 source 或者. 可以避免这个问题)

5. 实战脚本案例

案例 1:一键部署 vsftpd

一键部署vsftpd服务,并将服务设置为开启自启

[root@server ~]# vim /root/vsftpd.sh              #1.编写脚本
#!/bin/bash
#这个脚本是用于一键部署vsftpd服务,将服务启动且设置为开机自启
dnf -y install vsftpd
systemctl enable vsftpd --now
#查看vsftp服务端口号
ss -nutlp | grep :21

[root@server ~]# chmod  +x  /root/vsftpd.sh          #2.为脚本增加x执行权限
[root@server ~]# /root/vsftpd.sh                     #3.执行脚本
[root@server ~]# ss  -nutlp | grep :21               #验证服务确实已经启动
案例 2:一键创建用户并设置密码

一键创建用户lisi,并且为lisi用户设置密码为123

[root@server ~]# vim /root/user.sh                  #1.编写脚本
#!/bin/bash
#这个脚本是用于一键创建lisi用户,并且将lisi用户密码设置为123的脚本
useradd  lisi
echo 123 | passwd  --stdin lisi

[root@server ~]# chmod  +x  /root/user.sh          #2.为脚本增加x执行权限
[root@server ~]# /root/user.sh                     #3.执行脚本
[root@server ~]# id lisi                           #查看lisi用户已经成功创建

四、Shell 变量(核心)

1. 变量基础

  • 定义:用固定名称存放的可能会变化的值
  • 作用:提升可读性,简化代码,方便在脚本中重复使用。
  • 变量特性:一次定义,多次使用

(命令行中定义的变量属于临时定义,关闭窗口就会失效,想要永久定义需要在配置文件中声明)

2 定义/赋值变量

  • 定义/赋值变量:变量名=值
    • 注意:变量名要写在=的左边,值要写在=的右边,=左右两边不允许有空格
    • 变量的值是覆盖关系,定义的新的值会覆盖旧的值
[root@server ~]# name=zhangsan          #定义变量name,值为zhangsan
[root@server ~]# age=18                 #定义变量age,值为18
[root@server ~]# x=15                   #定义变量x,值为15

3. 变量命名规范

  • 建议变量在命名的时候尽量遵循小驼峰命名法、尽量不使用汉字、拼音、拼音简写
  • 小驼峰命名法:
    • 如果变量名由一个单词组成,那么这个单词全部小写,例如:age、school
    • 如果变量名由多个单词组成,那么第一个单词全部小写,后边的每个单词首字母大写,如:
    • myAge、userName、myLinuxScore
  • Shell中的变量在命名的时候仅支持:字母、数字、下划线严格区分大小写
    • 禁止:纯数字、数字开头、特殊符号 (一般情况下,不要使用命令当作变量名)
[root@server ~]# a1b2c3=zhangsan              #正确
[root@server ~]# ABC_abc_123=hello            #正确
[root@server ~]# 1ab2c3=15                    #错误,变量不可以数字开头
[root@server ~]# a1)cc=20                     #错误,变量不可以包含特殊符号)

4. 变量基本操作

  • 调用/引用变量值:$变量名${变量名}
  • 输出变量值:echo $变量名${变量名} (带{}为标准写法,推荐使用)
[root@server ~]# X=RHEL                  #定义变量X,值为RHEL
[root@server ~]# echo $X                 #输出变量X的值
RHEL
[root@server ~]# echo $X9.6              #这里将X9当成一个变量了,使用会输出变量X9的值,拼接.6,但没有X9变量,是空的
.6
[root@server ~]# echo ${X}9.6            #输出变量X的值,拼接9.6,使用${}圈定变量边界
RHEL9.6

5.取消变量

  • 退出定义变量的Shell环境(终端、远程连接)时,变量会自动失效
  • 也可以手动取消变量:unset 变量名
[root@server ~]# X=RHEL              #定义变量X,值为RHEL
[root@server ~]# echo $X             #输出变量X的值
RHEL
[root@server ~]# unset X             #取消变量X
[root@server ~]# echo $X             #输出变量X的值,空

五、Shell 四大变量类型

在这里插入图片描述

1. 自定义变量

  • 用户自己定义,可自由修改、赋值。
  • 示例:批量创建用户脚本
[root@server ~]# mkdir -p /root/shell/day0{1..5}        #创建5个目录,每天一个目录
[root@server ~]# vim  /root/shell/day01/useradd.sh      #创建 创建用户的脚本
#!/bin/bash
#定义用户名变量 和 密码变量
name=mike
password=123456
#创建用户,并且为用户设置密码
useradd $name
echo $password | passwd --stdin $name
[root@server ~]# chmd  +x  /root/shell/day01/useradd.sh  #为脚本增加x执行权限
[root@server ~]# /root/shell/useradd.sh                  #执行脚本,创建用户并设置密码
[root@server ~]# id mike                                 #查看用户已经创建

(mkdir -p /root/shell/day0{1..5} 意思是匹配创建1~5的同级目录)

2. 位置变量(脚本传参)

  • 在脚本执行时,提供命令行参数,并将参数传入脚本内部
    • 位置变量使用:整数表示(整数表示(1、2...2、...、{10})数字为序号

示例:动态创建用户

[root@server ~]# vim  /root/shell/day01/useradd.sh       #使用位置变量,升级脚本
#!/bin/bash
#创建用户,并且为用户设置密码,用户名密码使用位置变量,在执行脚本时传递位置变量的值
useradd $1
echo $2  | passwd --stdin $1

[root@server ~]# /root/shell/useradd.sh  lucy  123       #执行脚本,传递用户名 和 密码
[root@server ~]# id lucy                                 #查看用户已经创建

简单总结: 位置变量就是脚本的“入口参数” 就是用户执行脚本时,后面跟着输入的内容,脚本里用 $1 $2 $3... 接收。


常用位置变量一览表

位置变量作用
$0脚本自己的文件名(如 test.sh)
$1第1个参数
$2第2个参数
$3第3个参数
$#一共传了多少个参数(数字)
$@所有参数(分开显示)
$*所有参数(合并成一串)

示例:

#!/usr/bin/env bash

echo "脚本名:$0"
echo "总参数个数:$#"
echo "第1个参数:$1"
echo "第2个参数:$2"
echo "所有参数:$@"

执行:

./test.sh apple banana

输出:

脚本名:./test.sh
总参数个数:2
第1个参数:apple
第2个参数:banana
所有参数:apple banana

3. 环境变量

  • 配置文件:

    • /etc/profile(全局配置文件, 优先级低)、~/.bash_profile(当前用户,保存于当前用户家目录之下,优先级高) 全局变量:设置系统级路径、语言、共享库路径 用户变量:设置用户私有别名、自定义路径、启动脚本
  • 特点:系统预设,值随环境变化,大写命名。

  • 查看所有环境变量:env

  • 常用环境变量: 在这里插入图片描述

PATH用于保存当前系统的命令检索路径(将脚本放入这些目录可像命令一样直接执行)

在PATH变量中的路径,其目录下边的程序文件可以像命令一样使用,遵循从左向右依次匹配,匹配即停止

[root@server ~]# echo $PATH                      #查看PATH变量的值,即PATH变量中保存的路径
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@server ~]# vim /root/shell/day01/hello.sh  #编写脚本
#!/bin/bash
echo "Hello,I love Linux"

[root@server ~]# chmod +x /root/shell/day01/hello.sh
[root@server ~]# cp   /root/shell/day01/hello.sh   /usr/local/bin  #拷贝脚本至PATH变量的任意目录
[root@server ~]# hello.sh                         #脚本可以像命令一样使用

4. 预定义变量(系统自带,不可赋值)

  • 预定义变量用来保存脚本程序的执行信息
  • 预定义变量可以直接使用,不能为这些变量手动赋值

在这里插入图片描述 (实战工作过程中,$?$$ 使用频率非常高,非常重要)

[root@server ~]# vim /root/shell/day01/pre.sh
#!/bin/bash
echo  $0  #输出当前进程名或脚本名
echo  $*  #输出具体的位置变量的值
echo  $@  #输出具体的位置变量的值,与$*作用一样
echo  $#  #输出位置变量的总数
echo  $$  #输出当前进程的PID(进程号)
[root@server ~]# chmod +x  /root/shell/day01/pre.sh            #为脚本赋予x执行权限
[root@server ~]# /root/shell/day01/pre.sh  aa  tom  123  test  #执行脚本验证
/root/shell/day01/pre.sh
aa tom 123 test
aa tom 123 test
4
2054

实战建议高频使用:$? 判断命令是否执行成功($?仅保存上一条命令的错误) 0表示上一条命令执行正确,1或其他数字表示上一条命令执行异常(不正确)

[root@server ~]# ifconfig | head -2                  #执行正确命令
[root@server ~]# echo $?                             #查看上一条命令的返回值,0表示正确
0
[root@server ~]# adfasdf                             #执行错误命令
-bash: adfasdf: 未找到命令
[root@server ~]# echo $?                             #查看上一条命令的返回值,非0表示不正确
127

六、变量赋值与作用范围

1. 三种引号区别

  • 双引号 "":双引号中允许使用 $ 解析变量
  • 单引号 '':单引号中不解析变量,原样输出
  • **反撇号 `` 与 ():将命令结果赋值给变量(注意!其中必须包含命令)(反撇号中的内容优先进行,执行完毕的结果再赋值给变量。包括()**:将命令结果赋值给变量(注意!其中必须包含命令) (反撇号中的内容优先进行,执行完毕的结果再赋值给变量。包括 ()也会优先执行括号中的内容)
[root@server ~]# X=10
[root@server ~]# echo "$X"                   #双引号允许引用特殊符号的特殊含义
10
[root@server ~]# echo '$X'                    #单引号不允许引用特殊符号的特殊含义
$X
[root@server ~]# text=`head -1 /etc/passwd`  #将命令的输出结果作为变量text的值
[root@server ~]# abc=$(head -1 /etc/passwd)  #将命令的输出结果作为变量abc的值

2. read 交互式取值

(本质上是交互式变量赋值)

  • read 从键盘读入变量值完成赋值
  • 格式: read [ -p "提示信息" ] 变量名
    • -p "提示信息"
    • -t 可指定超时秒数(注:read内置超时时间,超时自动退出,也可以通过-t设置)
    • -s设置不在终端显示输入的内容(通常用于隐藏密码)
[root@server ~]# vim /root/shell/day01/read.sh           #编写脚本
#!/bin/bash
read -p "请输入用户名:"   name
read -p "请输入密码:" -s  pass
useradd "$name"
echo "$pass" | passwd --stdin "$name"

[root@server ~]# chmod +x /root/shell/day01/read.sh      #为脚本增加x执行权限
[root@server ~]# /root/shell/day01/read.sh               #运行脚本
请输入用户名:jerry
请输入密码:
[root@shellwork ~]# read -t 3 -p "请输入用户名: " name   #设置三秒超时
请输入用户名: [root@shellwork ~]# 

3. 局部 vs 全局变量

  • 局部变量:
    • 新定义的变量默认只在当前Shell环境中有效,无法在子Shell环境中使用(子环境相当于父环境进程的子进程)
  • 全局变量:
    • 全局变量在当前Shell及Shell环境中均有效(但是不会对父shell环境生效)
    • 使用:export 变量名[=值],声明全局变量
    • 使用:export -n 变量名取消全局变量作用,使该变量仅在当前Shell环境生效 (修改对应配置文件可以使全局变量在所有环境中生效) 局部变量和全局变量演示:
[root@server ~]# city=Beijing          #定义局部变量值
[root@server ~]# echo $city            #在当前Shell环境生效
Beijing
[root@server ~]# sh                    #切换到子Shell环境
sh-4.4# echo $city                     #输出局部变量值 不生效

sh-4.4# exit
[root@server ~]# export city           #将变量声明为 全局变量
[root@server ~]# sh                    #切换到子Shell环境
sh-4.4# echo $city                     #输出全局变量值 生效
Beijing
sh-4.4# exit
[root@server ~]# export school=hopeschool  #直接声明全局变量,也可以
[root@server ~]# echo $school          #在当前Shell环境查看变量school的值
[root@server ~]# sh                    #切换到子Shell环境
sh-4.4# echo $school                   #在子Shell环境查看变量school的值
Beijing
sh-4.4# exit

七、Shell 数值运算

  • 四则运算
    • 加法: num1 + num2
    • 减法: num1 - num2
    • 乘法: num1 * num2
    • 整除: num1 / num2
  • 取余数运算
    • 求模: num1 % num2

1. 6.1 $[] 算式

  • 使用$[ ]$(( )) 表达式
  • 格式:$[整数1 运算符 整数2 .. ..]$((整数1 运算符 整数2 .. ..))
  • 计算结果替换表达式本身,可结合echo命令输出 注意![][] 和 (( ))算式只能输出整数内容
[root@server ~]# echo    $[1+2]
[root@server ~]# echo    $[2*3]
[root@server ~]# echo    $((10/2))

[root@server ~]# x=15
[root@server ~]# y=3
[root@server ~]# echo    $[x+y]            #使用变量运算
[root@server ~]# echo    $[x*y]
[root@server ~]# echo    $[x%3]
[root@server ~]# echo   $[x%2]
  • 编写shell脚本,实现快速计算购买饮料花了多少钱
[root@server ~]# vim  /root/shell/day01/shop.sh     #编写脚本
#!/bin/bash
# 饮料购买计算器,只能计算整数
#变量说明:price变量为饮料单价,num变量为购买的数量,total变量为总消费金额
read -p "一瓶饮料多少钱:" price
read -p "你想买几瓶:" num

total=$[ price * num ]
echo "总共需要:$total 元"

[root@server ~]# chmod +x /root/shell/day01/shop.sh     #为脚本增加x执行泉下你
[root@server ~]# /root/shell/day01/shop.sh              #执行脚本测试
一瓶饮料多少钱:5
你想买几瓶:2
总共需要:10 元

2. 自增/自减

  • 使用$[ ]运算 或者使用let命令 (后)自增: x++先以当前值执行,再使x+1。 每执行一次,使x的值变成x+1) (后)自减*: x- - (先以当前值执行,再使x-1。每执行一次,使x的值变成x-1) (前)自*: ++x先使x=x+1,再执行当前命令。 每执行一次,使x的值变成x+1) (前)自减: - -x (先使x=x-1,再执行当前命令。每执行一次,使x的值变成x-1) (自增/自减多用于循环语句)

补充: x+=n:相当于x=x+n x-=n:相当于x=x-n

[root@server ~]# x=2
[root@server ~]# echo $[x+=2]            #使变量x在自身的基础上+2,并输出(变量会改变)
4
[root@server ~]# echo $[x*=2]            #使变量x在自身的基础上x2,并输出(变量会改变)
8
[root@server ~]# x=2
[root@server ~]# let x++                 #使变量x自加1
[root@server ~]# echo $x                 #输出变量x
[root@server ~]# let x++                 #使变量x自加1
[root@server ~]# echo $x                 #输出变量x
[root@server ~]# let x+=3                #使变量x自加3
[root@server ~]# echo $x                 #输出变量x

因为x++是“后自增”,也就是说它是先以x当前值执行,然后再让x+1。 例如: 执行echo [x++]会输出x当前的值,然后执行x++x=x+1,所以执行echo[x++]会输出x当前的值,然后执行x++让x=x+1,所以执行echo [x++]后,输出的x值是增加之前的值,真实的x值已经+1了(x- -同理)

同样的,++x是“前自增”,就会是先使x+1,再执行命令输出

3. 小数运算(bc 计算器)

  • $[ ]不支持小数运算,若想进行小数运算可以使用bc计算器
  • bc计算器需要安装软件包:bc
  • bc支持交互式和非交互式两种方式计算,scale=n可以约束小数位
[root@server ~]# dnf -y install bc       #安装计算器程序
[root@server ~]# bc                      #进入bc计算器 交互式命令行
12.34*11.11  #计算小数乘法,默认保留小数点后1位小数
137.09
scale=4                                  #指定保留小数点后2位小数
12.34*11.11
137.0974
quit                                      #退出计算器
[root@server ~]# echo "scale=2; 10/2"  | bc  #非交互式运算

bc的非交互式运算: echo "scale=n; x+y" | bc 脚本中通过bc的非交互式运算来进行细节运算

4. 数值比较

  • bc支持的比较操作符: >、>=、<、<=、==、!=
  • 格式:echo "数值1 比较符号 数值2" | bc
  • 表达式成立则返回1,不成立返回0 (返回值类似布尔值)
[root@server ~]# echo "1>2" | bc
0
[root@server ~]# echo "5>2" | bc
1
[root@server ~]# A=3.1
[root@server ~]# B=6.28
[root@server ~]# echo "$A>$B"  #标量之间的比较
0 

八、Day01 核心总结

  1. 理解 Shell 作用与 bash 解释器特性
  2. 掌握脚本编写→赋权→运行全流程
  3. 牢记四大变量类型与使用场景
  4. 熟练整数运算、小数运算、$? 判断状态
  5. 能编写自动化部署、用户创建等实用脚本