一、Shell 介绍

1.1 Shell 简介

Shell 是一个用 C 语言编写的程序,用户通过 Shell 可以访问操作系统内核提供的服务。(并不能作为独立开发程序的弱语言,区别去python、go、java、php、C等强语言)

它类似于 Windows 系统中的 command 或 cmd.exe,既可作为交互式命令解释器使用,也可作为脚本编程语言执行复杂的任务。

Shell脚本是一种专为Shell环境编写的程序。Shell编程通常指的是编写Shell脚本,而非开发Shell程序本身。

Shell脚本主要有以下用途:

  • 自动化软件安装部署:例如快速搭建LAMP架构服务

  • 高效系统管理:实现批量用户添加等操作

  • 定时备份任务:自动执行数据库备份等关键操作

  • 智能数据分析:自动处理网站访问日志等数据

1.2 Shell解释器

shell编程与常规编程语言类似,只需要具备两个基本工具:一个可以用来编写代码的文本编辑器和一个能够解释执行脚本的解释器即可。

一般centos常用的解释器有/bin/bash(bash易用且免费)

二、Shell脚本入门

2.1Shell脚本编写

使用vim文本编辑器创建一个格式为.sh的文件

示例:#!/bin/bash。其中#!是一个约定标记,指定脚本使用的解释器路径

2.2Shell脚本的执行

执行之前需要赋予文件具有x执行的权限:

使用命令chmod a+x test.sh添加权限

执行的方式有五种:

  1. ./test.sh在当前目录下使用相对路径执行文件

  2. /root/test/test.sh以绝对路径的方式执行

  3. sh /root/test/test.sh作为解释器参数执行

  4. source /root/test/test.sh使用source命令执行

  5. sh < /root/test/test.sh

  • 一个完整的shell程序包括:

    1.变量定义

    2.数据类型

    3.运算符

    4.流程控制语句(默认按顺序执行)

    5.数组

    6.函数(也称之为方法)


三、Shell程序:变量

3.1 语法格式

变量的定义格式:变量名=值(等号两边不能有空格)

变量的名字是由开发者定义的,通常在shell定义格式为:一个小写字母单词、多个单词组成时每个单词之间使用"_"分隔

例如:user_name=zhangsan

3.2 变量使用

1、利用$变量名${变量名}使用变量。

示例:

[root@paopao test]# echo $user_name
zhangsan
[root@paopao test]# echo ${user_name}
zhangsan

[root@paopao test]# ./test.sh
zhangsan
zhangsan
  • 花括号加不加都行,加花括号是为了帮助解释器区分变量的边界。

2、已定义的变量可以重新被定义

示例:

[root@paopao test]# ./test.sh
zhangsan
lisi
[root@paopao test]#

3、可以使用readonly命令将变量定义为只读变量,不能修改或删除。

示例:

[root@paopao test]# ./test.sh
zhangsan
./test.sh:行7: user_name: 只读变量
zhangsan

4、可以使用unset命令删除变量,但是不能删除只读变量。

示例:

[root@paopao test]# ./test.sh
./test.sh: 第 4 行:unset: user_name: 无法反设定: 只读 variable
zhangsan
./test.sh:行7: user_name: 只读变量
zhangsan

3.3 变量类型


变量分为局部变量和全局变量

  • 局部变量仅在当前shell实例中有效

示例:

[root@paopao ~]# echo -e '#!/bin/bash\nname=zhansan\necho $name' test/test.sh
[root@paopao ~]# cat test/test.sh
#!/bin/bash
name=zhansan
echo $name
[root@paopao ~]# ./test/test.sh
zhansan
[root@paopao ~]# echo -e '#!/bin/bash\necho $name' test/test1.sh
[root@paopao ~]# cat test/test1.sh
#!/bin/bash
echo $name
[root@paopao ~]# sh ./test/test1.sh
  • 全局变量(也叫环境变量)在所有程序都可以用。某些程序需要依赖环境变量才能正常运行。

    可以使用set命令查看当前环境变量

4.4 设置环境变量

  1. 修改配置文件

    export变量名=变量值添加到/etc/profile文件中(将shell变量输出为环境变量)

    示例:echo "export ens33=/etc/sysconfig/network-scripts/ifcfg-ens33" >> /etc/profile

  2. 执行配置文件

    使用命令source /etc/profile(让修改后的配置信息立即生效)

  3. 使用方法

    命令 $变量名

    示例:

    [root@paopao ~]# cat $ens33
    TYPE="Ethernet"
    PROXY_METHOD="none"
    BROWSER_ONLY="no"
    BOOTPROTO="dhcp"
    DEFROUTE="yes"
    IPV4_FAILURE_FATAL="no"
    IPV6INIT="yes"
    IPV6_AUTOCONF="yes"
    IPV6_DEFROUTE="yes"
    IPV6_FAILURE_FATAL="no"
    IPV6_ADDR_GEN_MODE="stable-privacy"
    NAME="ens33"
    UUID="3e245021-f737-474e-965f-3fc061c34883"
    DEVICE="ens33"
    ONBOOT="yes"

4.5 多行注释

  • :<<!...............!

    将其中的内容全部被注释掉,不管写多少行都不会执行

    示例:

    #!/bin/bash
    ​
    echo "这行会执行"
    ​
    :<<!
    echo "这行不会执行"
    echo "这行也不会执行"
    echo "注释可以写很多行"
    !
    ​
    echo "这行也会执行"

四、字符串

在Shell编程中,字符串是最常用且最实用的数据类型 (实际上除了数字和字符串,其他数据类型相对较少)。字符串可以使用单引号、双引号,甚至直接书写而不加任何引号。

4.1 单引号和双引号的区别

  • 单引号:原样输出,不解析变量

示例:

[root@paopao ~]# vim test/test1.sh
[root@paopao ~]# cat test/test1.sh
#!/bin/bash
name='zhangsan'
who='my name is $name'
echo $who
[root@paopao ~]# sh test/test1.sh
my name is $name
  • 双引号:可解析变量和转义字符

示例:

[root@paopao ~]# vim test/test1.sh
[root@paopao ~]# cat test/test1.sh
#!/bin/bash
name='zhangsan'
who="my name is $name"
echo $who
[root@paopao ~]# sh test/test1.sh
my name is zhangsan

4.2 字符串长度


在字符串前加上#符输出的结果不再是字符串,而是字符串的长度。

示例:

[root@paopao ~]# vim test/test.sh
[root@paopao ~]# cat test/test.sh
#!/bin/bash
name=zhansan
echo ${name}
echo ${#name}
[root@paopao ~]# test/test.sh
zhansan
7

4.3 提取字符串


  • 在字符串后面加:n,表示只输出n个后的字符

示例:

[root@paopao ~]# vim test/test.sh
[root@paopao ~]# cat test/test.sh
#!/bin/bash
name=zhansan
echo ${name:4}
[root@paopao ~]# test/test.sh
san
  • 在字符串后面加:n:m,表示只输出第n个和第m个之间的字符

示例:

[root@paopao ~]# vim test/test.sh
[root@paopao ~]# cat test/test.sh
#!/bin/bash
name=zhansan
echo ${name:3:6}
[root@paopao ~]# test/test.sh
nsan
  • PS:当字符串中间有空格时,空格也算是一个字符存在。

五、脚本参数

在执行程序的时候可以在后面跟上参数进行传递。在脚本中,$n代表参数。$0表示当前脚本名称

5.1 传递方式

格式为:./shell程序[空格]参数1[空格]参数2...

示例:

[root@paopao test]# vim test.sh
[root@paopao test]# cat test.sh
#!/bin/bash
name1=$1
name2=$2
echo $name1
echo $name2
[root@paopao test]# ./test.sh 1 2
1
2

5.2 特殊的参数变量

变量 说明
$# 传递到脚本的参数个数
$* 以一个字符串显示所有参数
$$ 脚本运行的当前进程ID
$! 最后一个后台进程ID
$@ 与$*相同,使用时加引号,在引号中返回每个参数
$? 上一条命令的退出状态,0表示没有错误,其它表示有错误(1~255)

示例:

[root@paopao test]# vim test.sh
[root@paopao test]# cat test.sh
#!/bin/bash
echo "第一个输入的参数是:$1"
echo "一共输入了$#个参数"
echo "输入的参数分别是:$*"
echo "当前脚本运行的进程ID是:$$"
[root@paopao test]# ./test.sh 1 2 3 4
第一个输入的参数是:1
一共输入了4个参数
输入的参数分别是:1 2 3 4
当前脚本运行的进程ID是:16942
​
  • $?可以用来判断上一个命令执行是否成功

当得到的值非0时代表上一个命令执行失败

当得到的值是0时代表上一个命令执行成功

示例:

[root@paopao test]# ls abc
ls: 无法访问abc: 没有那个文件或目录
[root@paopao test]# echo $?
2
[root@paopao test]# ls
test.sh
[root@paopao test]# echo $?
0
  • $*和$@的区别

在循环案例中$*得出的值会以一个整体的方式来显示所有参数,而$@则是以列表的方式显示所有参数。


六、运算符

Shell和其他编程语言一样支持包括:算术、关系、逻辑、字符串等运算符。

6.1 算术运算符

原生的/bin/bash不支持简单的数学运算,但是可以通过其他命令来实现。

例如:

  1. expr,用来完成求值操作。

示例:

[root@paopao test]# vim test.sh
[root@paopao test]# cat test.sh
#!/bin/bash
​
val=`expr $1 + $2`
echo "$1 + $2=$val"
[root@paopao test]# ./test.sh 1 2
1 + 2=3 
​
  • PS:运算符与运算数之间必须保留空格

完成的表达式需要用反引号`包裹,注意不是单引号

  1. read交互命令

常用选项: -p 在脚本中用于交互式读取用户输入的命令

示例:

[root@paopao test]# vim test.sh
[root@paopao test]# cat test.sh
#!/bin/bash
​
read -p "请输入你的名字:" name
read -p "请输入你的年龄:" age
echo "$name先生您好;"
echo "祝您$age岁生日快乐!"
[root@paopao test]# ./test.sh
请输入你的名字:泡泡
请输入你的年龄:1
泡泡先生您好;
祝您1岁生日快乐!

-n 控制输入数量,达到n时自动结束输入

示例:

[root@paopao test]# vim test.sh
[root@paopao test]# cat test.sh
#!/bin/bash

read -p "请输入百度的网址:" -n 13 code
echo ""
[root@paopao test]# ./test.sh
请输入百度的网址:www.baidu.com
[root@paopao test]#
  1. 还可以使用$(())、$[]进行算术运算

示例:$(())

[root@paopao test]# vim test.sh
[root@paopao test]# cat test.sh
#!/bin/bash

val=$(($1+$2))
echo "$1 + $2=$val"
[root@paopao test]# ./test.sh 1 2
1 + 2=3

示例:$[]

[root@paopao test]# vim test.sh
[root@paopao test]# cat test.sh
#!/bin/bash
​
sum=$[1+2]
echo "sum=$sum"
[root@paopao test]# ./test.sh
sum=3
​

6.2 关系运算符

PS:关系运算符只支持数字,不支持字符串,除非字符串的值是数字。

  • 数字的关系运算符有:< 、> 、<= 、>= 、!= 、==。

运算符 含义
-eq 检测两个数是否相等,相等返回 tue(同==)
-ne 检测两个数是否不相等,不相等返回 tue(同!=)
-lt 小于应用于: 整型比较。例:10 -lt 5(同<)
-gt 检测左边的数是否大于右边的,如果是,则返回true(同>)
-le 小于或等于 应用于: 整型比较(同<=)
-ge 大于或等于 应用于: 整型比较(同>=)

6.3 逻辑运算符

运算符 含义
-a 两侧表达式判断都成立(and)
-o 一侧表达式判断成立(or)
  • &&表示并且(and)

  • ||表示或者(or)

1、直接通过echo方式使用逻辑运算,运算符: && 、 ||

例如:[ -f /opt/1.txt ] && echo ture || echo false

[ -f /opt/1.txt ]的返回值为0时则输出ture,否则输出为false

示例:

[root@mywork opt]# ls
rh
[root@mywork opt]# [ -e rh ] && echo ture
ture
[root@mywork opt]# [ -e rh ] && echo ture || echo false
ture
[root@mywork opt]# [ -e hh ] && echo ture || echo false
false

2、在if语句中使用逻辑运算,运算符: -a 、 -o

3、条件判断不同写法

示例:3种不同写法

[root@mywork opt]# a=10
[root@mywork opt]# [ $a -ne 6 ] && [ $a -gt 9 ]
[root@mywork opt]# echo $?
0
[root@mywork opt]#  [ $a -ne 6 -a $a -gt 9 ]
[root@mywork opt]# echo $?
0
[root@mywork opt]# [[ $a -ne 6 && $a -gt 9 ]]
[root@mywork opt]# echo $?
0

6.4 字符串运算符

运算符 含义
-n 字符串长度不为零(非空字符串)
-z 字符串长度为零(空字符串)
= 判断两个字符串是否相同
!= 判断两个字符串是否不相同
  • 在Shell脚本中,变量引用建议用双引号包裹(如"$var"),避免未定义的变量或含空格的字符串引发语法错误。

  • 等号(=)和不等号(!=)两侧需保留空格,否则会被视为赋值操作或语法错误。

if中使用

例如:if [ -n "$var" ]; then ...

6.5 文件测试运算符

运算符 含义
-f 存在且是普通文件
-d 存在且是目录
-s 文件存在且不为空
-e 文件或目录存在
-r 存在且当前用户有读的权限
-w 存在且当前用户有写全权限
-x 存在且当前用户有执行权限
  • 所有测试运算符都需在[ ]内使用,括号两边还需保留空格

  • 测试结果可通过$?获取,返回值为0说明成立,1说明不成立

例如:[ -e /opt/1.txt ]

在使用$?查看返回值是否为0

示例:

[root@mywork opt]# ls
rh
[root@mywork opt]# [ -e rh ]
[root@mywork opt]# echo $?
0
[root@mywork opt]# [ -e hh ]
[root@mywork opt]# echo $?
1

七、if判断

if 是 Shell 中的条件判断语句。断条件是否为真,为真就执行 then 里的代码,最后用 fi 结束。

7.1 单分支

语法:if [ 判断条件 ]; then...fi

示例:

#!/bin/bash
if [ $1 -ne 2 ]; then
    echo "$!不等于2"
fi
#!/bin/bash
if cat /etc/passwd >> /dev/null
  then
    echo "文件存在"
fi

7.2 双分支

语法:if [ 判断条件 ]; then...else...fi

示例:

#!/bin/bash
if [ $1 -ne 2 ]; then
    echo "$1不等于2"
else
    echo "$1等于2"
fi

7.3 多分支

语法:if [ 判断条件 ]; then...elif[ 判断条件 ]; then...else...fi

示例:

#!/bin/bash
if [ $1 -lt 2 ]; then
    echo "$1小于2"
elif [ $1 -ge 2 ]; then
    echo "$1大于等于2"
else
    echo "$1等于2"
fi

7.4嵌套分支

基本语法结构

#!/bin/bash
if 条件1; then
    if 条件2; then
        执行A
    else
        执行B
    fi
else
    执行C
fi

建议:嵌套超过 2 层时,优先考虑用 elifcase 替代,代码更清晰。


八、case语句

语法:

case 变量值 in
模式 1)
命令序列 1
;;
模式 2)
命令序列 2
;;
esac

示例:

#!/bin/bash
read -p "请输入您的分数(0-100): " score
[[ $score -ge 85 && $score -le 100 ]] && a="great"
[[ $score -ge 70 && $score -lt 85 ]] && a="standard"
[[ $score -ge 0 && $score -lt 70 ]] && a="false"
case $a in
great)
    echo "$score 分,优秀!"
;;
standard)
    echo "$score 分,合格!"
;;
false)
    echo "$score 分,不合格!"
;;
*)
    echo "输入有误!"
esac

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐