Shell脚本编程

Shell脚本编程

简介

  • Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一 种程序设计语言。

  • Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的 服务。(翻译官,帮你翻译命令给内核执行)

相互之间的关系

  • Linux 的 Shell 种类众多,常见的有:

    • Bourne Shell(/usr/bin/sh或/bin/sh)
    • Bourne Again Shell(/bin/bash)
    • C Shell(/usr/bin/csh)
    • K Shell(/usr/bin/ksh)
    • Shell for Root(/sbin/sh)
  • 程序编程风格

    • 过程式:以指令为中心,数据服务于命令
    • 对象式:以数据为中心,命令服务于数据
    • shell是一种过程式编程
  • 过程式编程

    • 顺序执行
    • 循环执行
    • 选择执行
  • 编程语言分类

    • 编译型语言
    • 解释型语言(shell是一种解释型语言)

两种分类语言之间的区别

运行脚本

给予执行权限,通过具体的文件路径指定文件执行

直接运行解释器,将脚本作为解释器程序的参数运行

bash退出状态码

范围是0-255

脚本中一旦遇到exit命令,脚本会立即终止,终止退出状态取决于exit命令后面的数字

如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态

变量

变量命名

  • 命名只能使用英文字母,数字和下划线,首字母不能以数字开头

  • 中间不能够有特殊字符,可以使用_下划线

  • 不能使用标点符号

  • 不能使用bash中的关键字

1
2
3
4
5
6
7
8
9
10
11
12
有效命名:
RUNOOB
LD_LIBRARY_PATH
_var
var2
无效命名:
?var=123
user*name=runoob
语句给变量赋值
for file in `ls /etc`

for file in $(ls /etc)

使用变量

1
2
3
4
5
6
7
8
9
10
定义变量:
your_name="eagles"
使用变量:
echo $your_name
echo ${your_name}
建议使用{}号作边界
for skill in Ada Coffe Action Java; do
echo "I am good at ${skill}Script"
done
如果使用$skillScript,则将会输出空值

只读变量

1
2
3
4
5
#!/bin/bash
myUrl="http://www.google.com"
readonly myUrl
myUrl="http://www.runoob.com"
执行脚本后,显示只读变量无法修改

删除变量

1
2
3
4
#!/bin/sh
myUrl="http://www.runoob.com"
unset myUrl
echo $myUrl

变量种类

  • 本地变量:生效范围仅为当前shell进程;(其他shell,当前的子sehll进程均无效)

    • 变量赋值:name = “value”
  • 环境变量:生效范围为当前shell进程及子进程

    • 变量声明1:export name = “value”
    • 变量声明2:declare -x name = “value”
    • bash中有许多内建的变量环境:SHELL,PATH等等
  • 局部变量:生效范围为当前shell进程中某代码片断(通常指函数)

  • 位置变量: 2…来表示,让脚本在脚本代码中调用通过命令行传递给它的参数;

  • 特殊变量:? 0 * @ #

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$1,$2,…:对应调用第1,第2等参数
$0:命令本身
$*:传递给脚本的所有参数(把所有参数当作整体)
$@:传递给脚本的所有参数
$#:传递给脚本的参数的个数
案例1:
myecho.sh
#!/bin/bash
echo "命令本身是:$0"
echo "第一个参数是:$1"
echo "第二个参数是:$2"
echo "一共有$#个参数"
echo "所有参数是:$@"

案例2:判断所给文件的行数
linecount.sh
#!/bin/bash
linecount="$(wc -l $1|cut -d' ' -f1)"
echo "This file have ${linecount} lines"

数组

  • 语法格式

1
2
3
4
5
6
语法格式:array_name=(value1 ... valuen)
示例:
my_array=(A B C D)
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
  • 读取数组

1
2
3
4
5
6
7
8
读取数组:${array_name[index]}
获取数组中的所有元素:
my_array[0]=A
my_array[1]=B
my_array[2]=C
my_array[3]=D
echo "数组的元素为: ${my_array[*]}"
echo "数组的元素为: ${my_array[@]}"
  • 获取数组的长度

1
2
3
4
5
6
7
获取数组的长度:
my_array[0]=A
my_array[1]=B
my_array[2]=C
my_array[3]=D
echo "数组元素个数为: ${#my_array[*]}"
echo "数组元素个数为: ${#my_array[@]}"

算数运算

  • 运算符

1
2
3
4
5
+ ‐ * / % ** ...
增强赋值:
+=,‐=,*=,/=,%=
乘法符号有些场景中需要转义 : *\
bash有内建随机数生成器:$RANDOM
  • 完成算数运算

1
2
3
4
5
6
7
8
9
(1) let var(变量名)=算术表达式
(2) var=$[算术表达式]
(3) var=$((算术表达式))
(4) var=$(expr arg1 arg2 arg3 …) var=$(expr 1 + 2)
expr本身是一个命令,可以直接进行运算
[root@centos73 ~]# expr 1+2
1+2
[root@centos73 ~]# expr 1 + 2注意要空格才可以进行运算。乘法符号有些场景中需要转义,如*。也就是expr这个命令后面跟的是3个参数
3
  • 练习题

1
2
3
4
5
练习1:计算/etc/passwd文件中第10个用户的第20个用户的ID之和

练习2:传递两个文件路径参数给脚本,计算这两个文件之中所有空白行之和

练习3:统计/etc/,/var/,/usr/目录下有多少目录和文件

条件测试

测试命令:test EXPERSSION

1
2
3
4
5
6
7
8
num1=100
num2=100
if test $[num1] -eq $[num2]
then
echo '两个数相等!'
else
echo '两个数不相等!'
fi

数值测试

‐gt:是否大于

‐ge:是否大于等于

‐eq:是否等于

‐ne:是否不等于

‐lt:是否小于

‐le:是否小于等于

练习题,比较两个数的大小

1
2
3
4
5
6
7
8
9
10
[root@localhost ~]# cat diff.sh
#!/bin/bash
read -p "请输入两个整数" num1 num2
if [ $num1 -gt $num2 ];then
echo "$num1 > $num2"
elif [ $num1 -lt $num2 ];then
echo "$num1 < $num2"
else
echo "$num1 = $num2"
fi

字符串测试

1
2
3
4
5
6
7
8
==:是否等于
>:是否大于
<:是否小于
!=:是否不等于
=~:左侧字符串是否能够被右侧的PATTERN所匹配
Note:此表达式一般用于[[ ]]中
‐z “STRING”:测试字符串是否为空,空则为真,不空则为假
‐n “STRING”:测试字符串是否不空,不空则为真,空则为假

文件测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
简单的存在性测试:
‐a FILE :文件存在性测试,存在为真,否则为假
存在性及类型测试:
‐b FLIE:是否存在且为块设备文件;
‐c FILE:是否存在且为字符设备文件;
‐d FILE:是否存在且为目录文件;
‐f FILE:是否存在且为普通文件;
‐h FILE 或 ‐L FILE : 存在且为符号链接文件;
‐p FIEL :是否存在且为命名管道文件;
‐S FILE:是否存在且为套接文件;
文件权限测试:
‐r FILE:是否存在且可读
‐w FILE:是否存在且可写
‐x FILE:是否存在可执行
文件特殊权限测试:
‐u FILE:是否存在且拥有suid权限;
‐g FILE:是否存在且拥有sgid权限;
‐k FILE:是否存在且拥有sticky权限;
文件大小测试:
‐s FILE:是否存在且非空
文件是否打开:
‐fd:fd表示文件描述符是否已经打开且与某终端相关
‐N FILE:文件自动上一次读取之后是否被修改过;
‐O FILE:当前用户是否为文件的属主;
‐G FILE:当前有效用户是否为文件数组;
双目测试:
FILE1 ‐ef FILE2 :FILE1与FILE2是否指向同一个设备上的相同inode
FILE1 ‐nt FILE2:FILE1是否新于FILE2
FILE1 ‐ot FILE2:FILE1是否旧于FILE2

组合测试条件

1
2
3
4
5
6
7
8
9
10
11
12
逻辑运算符:
&&代表的意思是当前一个命令执行成功时会继续执行后续的命令,当前一个命令执行失败的时候不会执行后续的命令
||代表的意思是当前一个命令执行成功时不会继续执行后续的命令,当前一个命令执行失败的时候会执行后续的命令
第一种方式:
COMMAND1 && COMMAND2
COMMAND1 || COMMAND2
! COMMAND
第二种方式:
EXPRESSION1 ‐a EXPRESSION2
EXPRESSION1 ‐o EXPRESSION2
! EXPRESSION
Note:必须使用测试命令进行

选择执行

  • 单分支选择结构

1
2
3
if 判断条件;then
条件为真的分支代码
fi
  • 双分支选择结构

1
2
3
4
5
if 判断条件;then
条件为真的分支代码
else
条件为假的分支代码
fi
  • 多分支选择结构

1
2
3
4
5
6
7
if 判断条件;then
条件为真的分支代码
elif 判断条件;then
条件为真的分支代码
else
条件为假的分支代码
fi
  • 练习题

1
2
3
4
练习1:判断两个数是否相等

Note:if经常会与test命令一起使用
练习2:判断用户是否存在,如果不存在添加用户,并设置密码和用户相同
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 练习2
#!bin/bash
read -p "请输入用户名:" user
id $user &> /dev/null
thing="$(echo $?)"
# echo $thing
if test $[thing] -eq 0
then
echo "用户已存在"
else
useradd $user
echo $user | passwd --stdin $user &>/dev/null
echo -e "账户已id成功创建\n"
echo "密码已更新为账户名"$user
fi

用户交互

read命令

  • 常用选项:

    • ‐a:将内容读入到数组中
      • echo ‐n “Input muliple values into an array:”
      • read ‐a array
      • echo "get $

Shell脚本编程
https://xiaolaji.site/20220905/Shell脚本编程/
Author
Xiaolaji
Posted on
September 5, 2022
Licensed under