1.为什么要进行shell编程?
在Linux系统中,虽然有各种各样的图形化接口工具,但是shell仍然是一个非常灵活的
工具。
Shell不仅仅是命令的收集,而且是一门非常棒的编程语言。
您可以通过使用shell使大量的任务自动化,
因此,之所以要使用Shell 脚本是基于:
#简单性
Shell 是一个高级语言,通过它,你可以简洁地表达复杂的操作。
#可移植性
使用POSIX 所定义的功能,可以做到脚本无须修改就可在不同的系统上执行。
#开发容易
可以在短时间内完成一个功能强大又好用的脚本。
//参考:《Shell 脚本学习指南》
#shell特别擅长:
系统管理任务,尤其适合那些易用性、可维护性和便携性比效率更重要的任务。
2.谁需要学习 Shell 编程?
Linux运维工程师:
编写Shell程序进行服务集群管理。
Python和JavaEE程序员:
编写Shell脚本程序或者是服务器的维护,比如编写一个定时备份数据库的脚本。
大数据程序员:
编写Shell程序来管理集群。Shell 是什么?
//我们怎么用:
//做简单配置
//能看懂别人的脚本
//eg:
// 后面双网卡的配置
3.shell编程 (之前学习过C语言)
3.1 shell编程 对比 C编程
shell编程: (1.执行过程,2.开发效率,3.执行效率,4.移植性)
解释型语言
边翻译边执行 (ls cp(程序))
擅长文件处理,操作系统管理
开发效率高 // cp 1 2
执行效率低
移植性好
.c
编译型语言
先编译再执行 //gcc 编译 (.c ---> 机器代码)
擅长数据计算和数据处理
开发效率低
执行效率高
移植性差
3.2 shell脚本编程
3.2.1 shell发展简介
sh
bash shell gnu unix
c shell csh
k shell ksh ash
...
我们用的是:
bash,也就是 Bourne Again Shell,由于易用和免费,Bash 在日常工作中被广泛使用。
同时,Bash 也是大多数Linux 系统默认的 Shell。
在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,
所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash。
[注]:
Bash (the Bourne-Agian shell)由 Brian Fox 为GNU项目编写,目的是代替sh。
首次发布于1989年,作为GNU项目的一个程序广泛分布在Linux、Mac OS X、Cygwin上。
Brain Fox作为FSF的员工,首次开始工作是在1988年的1月10号,一年之后,
发布了.99的测试版本。
#!/bin/bash --- 表示指定当前shell脚本的解释器为 /bin/bash 这个解释器
【总结】
shell脚本的本质就是一系列shell命令的集合。
3.2.2 shell脚本编写
1.shell脚本编写流程:
1.vim XX.sh #!/bin/bash //编辑文件 shebang
2.编写脚本 //#!/bin/bash
3.chmod +x XX.sh //给执行权限
4. ./XX.sh //执行文件
注意:
# --- 第一行 不要写注释 这些
#!/bin/bash --- 表示当前这个shell脚本用哪个shell来解释执行
所有者 所属组 其它人
r w x - r w x - r w x
1 1 1 1 1 1 1 1 1
----- ----- -----
7 7 7 //0777
r w x - r w x - r w x
1 0 1 1 1 1 1 1 1
----- ----- -----
5 7 7 //0577
4.环境变量: env
PATH:系统中可执行文件的路径
PWD :当前所在的工作路径
HOME:当前登录用户的家目录
...
USERNAME=linux
USER=linux
PWD=/home/linux/shell
HOME=/home/linux
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/linux/tools/opt/FriendlyARM/toolschain/4.4.3/bin
HOME=/home/linux
PWD=/home/linux/2021code/shell/test_code
USER=linux
SHELL=/bin/bash
PATH=/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/linux/tool/opt/FriendlyARM/toolschain/4.5.1/bin:/home/linux/Qt5.5.1/Tools/QtCreator/binenv
//引用环境变量:
$PATH
echo --- printf
键(key)值(value)对
KEY=value
键(key) 相当于 C语言中的 变量名
值(value) 相当于 C语言中的 赋的值
5.位置变量: ./3.sh /etc/passwd 123 内置变量
main(int argc,char* argv[]) // a.out 1 2
@argc --- 命令行参数的个数
@argv --- 命令行参数对应的数组的首地址
$0: 脚本文件名
$1: 传入脚本的第一个参数
$2: 传入脚本的第二个参数
...
$9:
ls /etcpass
cp /etc/passwd 123 ;
$#:传入参数的个数 //argc
$?:上一句shell命令执行的结果
0 表示成功
$$:当前shell的PID --- $$ 21694 //进程的概念提示
//[说明]:
表 1 位置参数变量
位置参数变量 作 用
$n n 为数字,$0 代表命令本身,$1~$9 代表第 1~9 个参数,10 以上的参数需要用大括号包含, 如${10}
$* 这个变量代表命令行中所有的参数,把所有的参数看成一个整体
$@ 这个变量也代表命令行中所有的参数,不过 $@ 把每个参数区别对待
$# 这个变量代表命令行中所有参数的个数
//[说明]:
6.自定义的变量:
(1) 注意:
【1】.shell中数据是弱类型,默认识别为字符串类型
【2】不需要,先定义
【3】名字规则 ,遵循C的命名规则。 //(不要带空格)
不能带 $符号
[注]
给值的时候 等号两边不能有空格
var=123 (√)
var = 123 (x)
(2)shell脚本输入输出
read name
echo '$name'
a+b;
(3)shell中的引号
"":打印字符串,遇到$变量($name)则打印变量中的值(name变量的值)
'':打印字符串,遇到$变量依然打印 $变量 (原样输出)
``:将中间的字符串按照命令打印 (命令置换) //用命令结果 置换这条命令
练习1:
从终端输入两个数,并打印出这两个数
read
echo
7.read
read从标准输入读入一行, 并赋值给后面的变量,其语法为:
. read var
把读入的数据全部赋给var
. read var1 var2 var3
把读入行中的第一个单词(word)赋给var1,
第二个单词赋给var2,
……把其余所有的词赋给最后一个变量.
如果执行read语句时标准输入无数据,
则程序在此停留等侯,
直到数据的到来或被终止运行。
read var1 var2 var3
//此时,从键盘输入的数据,可以在一行,数据与数据间用空格隔开
read var1
read var2
//此时多个数据用回车 区分
8.expr
//字符串不能进行运算,需要专门命令 expr expression
运算:
expr
算术运算命令expr主要用于进行简单的整数运算,
#注意:
(1).运算符号两边要有空格
(2).注意对应的运算符是否需要转义
包括:
加(+)、减(-)、乘(\*)、整除(/)和求模(%)等操作。
9.分支语句:
1.if语句
if (表达式)
{
语句1;
}
else
{
语句2;
}
//双分支
if 条件
then
语句1
else
语句2
fi //fi
((c语言风格的表达式))
//双分支
if ((c语言风格的表达式))
then
语句1
else
语句2
fi //fi
条件的生成:
逻辑运算 关系运算 //C中
if 条件
then
语句1
else
语句2
fi //fi
//多分支
if 条件表达式
then
语句
elif [条件表达式] #else if (表达式)
then
语句
elif [条件表达式]
then
语句
else
语句
fi
//单分支
if [ $i -eq 10 -a $j -le 10 ]
then
fi
10.//条件的生成 --test的命令 //注意: test 执行结果为真 0
// 执行结果为假 1
man test
-a and &&
-o or ||
test -eq 相等
test 10 -eq $i
[ $i -eq 10 ]
man test
if( a == 10)
-ne 不相等
-gt 大于
-lt 小于
-ge 大于等于
-le 小于等于
[ $i -ge 0 -a $i -lt 59 ]
0<= a <59
条件的写法:
//命令的写法
test 10 -eq $i
//中括号
[ $i -eq 10 ] //注意: 中括号里面,前后都要有空格。
//C风格
(( c语言风格的表达式 ))
练习 4:
if 实现 成绩的打印
从终端接收一个成绩
0 - 59 打印不及格
60 - 69 及格
70 - 79 良好
80 - 89 中等
90 - 100 优秀
11.
test
-b 块设备文件 block test -b /dev/sda --- 硬盘
eg:
ls -l /dev/sda
-c 字符设备文件 char --- 鼠标,键盘
eg:
ls -l /dev/input/mouse0
-d 目录文件 directory
-f 普通文件 regular
-L 链接文件 link 类似 windows下的快捷方式
eg:
ln -s 源文件 链接文件名
-S 套接字文件 socket (本地socket/网络socket )
-p 管道文件 pipe (管道) //进程的通信
eg:
mkfifo fifo //创建管道文件fifo
练习 5:
从终端输入一个文件名,判断该文件的类型
12.case
switch(n)
{
case 1:
...
break;
default:
...
break;
}
//shell
case $num in
9)
语句
;; //C中的 --- break
8|6|5|4)
语句
;; //C中的 break
7)语句
;;
*)语句 //default
;;
esac //esac --->case 反着写
练习 7: 80
从终端接收一个成绩,
0 - 59 不及格
60 - 69 及格
70 - 79 中等
80 - 89 良好
90 - 100 优秀
13.循环语句://while //do-while //for
//c语言
while (表达式)
{
语句
}
//shell - test [ ] (())
while [ 条件 ]
do
语句
...
done
for
until
练习:
while实现1到100求和
for 循环:
for循环一般格式为:
//c
for (表达式1;表达式2;表达式3)
{
语句;
}
//shell
for var in item1 item2 ... itemN //for循环的条件
do //for循环的执行体
command1
command2
...
commandN
done
seq命令 表示打印一系列值:
seq LAST
seq FIRST LAST
seq FIRST INCREMENT LAST
练习:
for 试下 1~100 累加求和
//C语言风格的:
格式
for((exp1; exp2; exp3))
do
statements
done
语法:((表达式1,表达式2…))
特点:
1、在双括号结构中,
所有表达式可以像c语言一样可以进行计算,
如:a++,b--等。
2、在双括号结构中,
所有变量可以不加入:“$”符号前缀。
until
语法格式:
until condition
do
command
done
condition 一般为条件表达式,
如果返回值为 false,
则继续执行循环体内的语句,否则跳出循环。
以下实例我们使用 until 命令来输出 0 ~ 9 的数字:
实例
#!/bin/bash
a=0
until [ ! $a -lt 10 ]
do
echo $a
a=`expr $a + 1`
done
练习 6:
从终端输入一个文件名,如果该文件存在,
则修改其权限为777,如果该文件不存在,
则在当前目录创建tmp文件夹,并在文件夹下
创建该文件并修改权限为777