今天开始开始学习系统编程,首先要学的就是shell。
1.shell概述
1.1用户与硬件的交互
用户不能与硬件直接进行交互。不能也没有必要。
因为可能会对硬件造成不可挽回的损失或破坏。图形化界面可以辅助我们对硬件资源进行管理、使用,但是不是直接与硬件进行交互。为了安全、有效的对各种硬件资源进行使用、管理,我们大多数是基于操作系统内核来实现。
这样就可以形成一个有效的保护机制,在系统内核与用户之间架起一座桥梁。
shell就属于这座桥梁上的一部分。
1.2shell
shell既是一种语言,也是解析器
shell语言:类似C语言的一种编程语言,一般称为脚本语言。shell属于解释型语言。
拓展:像C/C++这类语言叫编译型语言,需要借助编译器全部完成编译后生成可执行文件,然后进行执行。
像python/java script这类语言叫解释型语言,由解析器逐行进行解释然后直接执行,边解释边执行。
shell解析器:shell除了是一种语言,还是一种解析器。
shell的功能:
1.可以帮助开发者,将一些繁琐或者需要重复执行的命令整合到一起进行统一执行。
例如:我想在磁盘中找到一个叫做“漫夜.txt”的文档,如果手动寻找需要大量cd ls
可以借助shell
2.后续工作中如果需要环境配置,可以借助shell
1.3shell脚本解析器
在Linux里面,shell脚本解析器有3种,分别是sh,ash,bash
我所用的Linux,默认的shell解析器是:bash
可以使用echo $SHELL查看你说用的解析器是啥。
1.4shell语言
类似与C语言的一种编程语言,称为shell脚本语言。有自己特定的语法与要求。
1.5脚本区别和环境配置
针对于环境配置,系统中存在两个shell脚本文件
/etc/profile:配置整个系统的环境shell脚本文件,在此处修改环境配置,整个Linux系统生效。
当用户第一次登录进来,此配置就可以生效
~/.bashrc:只配置当前用户的环境,在此处修改,只修改对应用户的环境配置。
2.shell文件
2.1shell脚本文件
shell脚本文件是以.sh为后缀的
2.2shell脚本语言的执行
shell脚本文件的执行有3种方式:需要注意,第二个方式前面有一个点
- bash + 脚本文件名
- . 脚本文件名
- chmod + xxx(权限) ,修改可执行权限后通过: ./shell脚本文件名
3种方法的区别:
解析器区别:
- ./ 用第一行代码指定的解析器执行(#!/bin/bash)
- bash 使用bash解析器解析执行,前面指定过的无效
- . 使用当前解析器进行解析执行
执行区别:
- ./ 与bash相同,都是新开一个shell解析器进行解释执行(可以理解为开了一个看不到的终端进行解释执行)
- . 在当前shell解析器解释执行(可以理解为在当前终端操作)
3.shell变量
3.1shell变量定义
变量名=初始化值
//赋值号左右两侧不允许有空格,否则就会报错
eg:
num=10
str="hello"
3.1.1变量的取值$
在shell中取值符是$
#!/bin/bash
echo "hello shell"
num=10
num2=$num #将num的值取出,赋给num2
echo "num2=$num2"
str="helloworld"
echo "str=$str"
3.1.2清除变量unset
#!/bin/bash
echo "hello shell"
num=20
# unset num #清除num变量
echo "num=$num"
3.1.3读取变量read
就相当于c语言中的scanf
3.1.4只读变量readonly
#!/bin/bash
echo "hello shell"
readonly num=0
echo "请输入num的值"
read num
# unset num #清除num变量
echo "num=$num"
输入之后,输出仍然为0
这既是readonly,将变量的值固定了
3.1.5脚本配置环境export
脚本配置换将export只与当前终端有关,无法修改其他终端。
如果用bash 或者 ./ 运行,前面说过,是另外开一个shell解析器,所以当前终端不起作用
3.2单引号和双引号的区别
num=100
echo "num=$num" #将""里面的内容解析后输出
echo 'num=$num' #将''里面的内容原封不动的输出
3.3系统预设变量(env中)
#!/bin/bash
num=100
echo "num=$num"
echo 'num=$num'
echo "today is $DATA"
echo "当前所在路径 $PWD"
echo "当前所在路径的家目录 $HOME"
3.4预设环境变量
$#:传给 shell 脚本参数的数量
$*:传给 shell 脚本参数的内容
$1、$2、$3、...、$9:运行脚本时传递给其的参数,用空格隔开
$?:命令执行后返回的状态
"$?"用于检查上一个命令执行是否正确(在 Linux 中,命令退出状态为 0 表示该命令正确执行,任何非 0 值表示命
令出错)。
$0:当前执行的进程名
$$:当前进程的进程号
#!/bin/bash
echo "参数的个数是 $#"
echo "参数的内容是 $*"
echo "参数1: $1"
echo "参数1: $2"
echo "参数1: $3"
echo "上一条指令执行结果 $?"
echo "当前执行的进程名:$0"
echo "当前执行的进程号:$$"
3.5脚本变量的特殊用法
- ``(数字键1左边的那个按键):将``引起来的内容作为系统命令
eg :echo"当前IP为:`ip addr`"
可以查看当前ip
\ 转义字符
- \n \a \r
需要加上-e才能生效
.
- ()小括号内的内容修改只有在小括号内才有效
- { } 大括号内的内容修改,在内外都起作用
#!/bin/bash
num=10
(
num=100
echo "在小括号内()num=$num"
)
echo "在小括号外()num=$num"
{
num=100
echo "在大括{}号内num=$num"
}
echo "在大括{}号外num=$num"
3.6条件测试语句
后续在写代码的时候,经常会遇到判断两个字符串是否相等、判断文本文档是否存在、以及两个数值是否相等等一系列问题。这个时候就需要用到条件测试语句。
测试格式:
- test condition
- [ condition ] 注意,condition左右两侧各一个空格
3.6.1文本测试
-e 是否存在
-d 是目录
-f 是文件
-r 可读
-w 可写
-x 可执行
-L 符号连接 #驱动
-c 是否字符设备 #驱动
-b 是否块设备 #驱动
-s 文件非空
#!/bin/bash
#格式1
test -e ./05.sh #判断文件是否存在
echo "$?" #展示上一条命令运行结果,如果为0,则上条命令执行正确,如果非0,则上条命令执行失败
test -d test #判断是否为文件夹
echo "$?"
#格式2
[ -e ./05.sh ]
echo "$?"
[ -d test ]
echo "$?"
3.6.2字符串测试
字符串测试,用来测试一个或两个字符串是否满足某个关系
格式1:
- test str_operator “str” #测试对象为1个字符串
- test “str1” str_operator “str2” #测试对象为2个字符
格式2
- [ str_operator “str” ]
- [ “str1” str_operator “str2” ]
str_operator 可以是:
= 两个字符串相等
!= 两个字符串不相等
-z 空串
-n 非空串
案例如下:
Shell
自动换行
#!/bin/bash
str1="hello"
str2="hello"
#格式1
test -z $str1 #判断str1是否为空 如果为空结果为0 否则为1
echo "$?"
test $str1 = $str2 #判断str1是否等于str2
echo "$?"
#格式2
[ -z $str1 ]
echo "$?"
[ $str1 = $str2 ]
echo "$?"
3.6.3数值测试
判断两个数值之间的关系
格式1:test num1 num_operator num2
格式2:[ num1 num_operator num2 ]
num_operator 可以是:
-eq 数值相等
-ne 数值不相等
-gt 数 1 大于数 2
-ge 数 1 大于等于数 2
-le 数 1 小于等于数 2
-lt 数 1 小于数 2
代码案例
#!/bin/bash
num1=10
num2=0
echo "请输入num2的值"
read num2
test $num1 -eq $num2
echo "$?" #查看上一个命令执行是否成功
test $num1 -ne $num2
echo "$?"
test $num1 -gt $num2
echo "$?"
test $num2 -gt $num1
echo "$?"
[ $num1 -lt $num2 ]
echo "$?"
3.6.4复合测试
&& (cmd1 && cmd2)
- cmd1执行成功,shell才会执行右边
|| (cmd1 || cmd2)
- cmd1执行失败,shell才会执行右边
#!/bin/bash
num1=0
echo "请输入num1的值"
read num1
[ $num1 -ge 10 ] && [ $num1 -ge 20 ]
echo "$?"
num2=0
echo "请输入num2的值"
read num2
[ $num2 -ge 20 ] || [ $num2 -ge 10 ]
echo "$?"
代码案例
num3=0
echo "请输入num3的值"
read num3
#test $num3 -ge 10 -a $num3 -le 20
[ $num3 -ge 10 -a $num3 -le 20 ]
echo "$?"
4.控制语句
if case for while until
4.1if语句
固定格式:最后要有个fi
if [条件 1]; then
执行第一段程序
else
执行第二段程序
fi
代码案例
#!/bin/bash
num=0
echo "请输入一个num值"
read num
if [ $num -ge 10 ];then
echo "你输入的值大于等于10"
else
echo "你输入的值小于10"
fi
4.2if else语句
格式:
if [条件 1]; then
执行第一段程序
elif [条件 2]; then
执行第二段程序
else
执行第二段程序
fi
代码案例:
#!/bin/bash
num=0
echo "请输入一个num值"
read num
if [ $num -ge 10 ];then
echo "你输入的值大于等于10"
elif [ $num -lt 5 ];then
echo "你输入的值小于5"
else
echo "啥也不是"
fi
4.3case语句
格式:
case $变量名称 in
“第一个变量内容”)
程序段一
;;
“第二个变量内容”)
程序段二
;;
*)
其它程序段
exit 1
esac #case反过来
#!/bin/bash
num=10
echo "请输入num"
read num
case $num in
10)
echo "你输入的是10"
;;
20)
echo "你输入的是20"
;;
*)
echo "你输入的不是10,也不是20"
exit 1
esac
4.4for语句
格式:
#初始值:变量在循环中的起始值
#限制值:当变量值在这个限制范围内时,就继续进行循环
#执行步阶:每作一次循环时,变量的变化量
for (( 初始值; 限制值; 执行步阶 ))
do
程序段
done
代码案例:
#!/bin/bash
declare -i sum #将sum强制当做int类型来处理
declare -i i
sum=0
i=0
for((i=0;i<=10;i++))
do
sum=$sum+$i
done
echo "$sum"
格式2:
for var in con1 con2 con3 ...
do
程序段
done
# 第一次循环 var的值是 con1
# 第二次循环 var的值是 con2
...
# 第n次循环 var的值是 conn
放几个con 就执行几次循环
#!/bin/bash
declare -i sum
declare -i i
sum=0
i=0
for i in 0 1 2 3 4 5 6 7 8 9 10
do
sum=$sum+$i
done
echo "$sum"
4.5while语句
格式:
while [ condition ] //condition如果满足为true 就一直执行while循环
do
程序段
done
案例:
#!/bin/bash
declare -i sum
declare -i i
i=0
sum=0
while [ $i -le 10 ] #i的值满足 <=10 都为true
do
sum=$sum+$i
i=$i+1
done
echo "$sum"
4.6until
格式:
until [ condition ] //condition如果满足为true,退出循环(与while相反)
do
程序段
done
#!/bin/bash
declare -i sum
declare -i i
i=0
sum=0
until [ $i -gt 10 ] #i的值满足 >10 until结束
do
sum=$sum+$i
i=$i+1
done
echo "$sum"
4.7break与continue
与C语言用法保持一致
5.函数
函数可以解决代码的重复性使用问题,可以优化代码的可读性、维护性、以及冗余性。
函数的格式1:
函数名() {
命令 ...
}
格式2:(推荐)
function 函数名() {
命令 ...
}
5.1当前源文件封装函数
#!/bin/bash
declare -i sum #将sum强制当做int类型
function my_add() #函数定义
{
sum=$1+$2 #1和2在此处可以理解为特殊用法,可以代表第一个参数与第二个参数
return $sum
}
my_add 10 20 #调用
echo "$?" #展示上一行代码运行结果,即30
拓展:declare的使用
declare [选项] [名称[=值]]
5.2其他源文件封装函数
代码案例:
#!/bin/bash
source 18.sh #source + 文件路径文件名 可以引用对应的资源
my_add 10 20 #调用
echo "$?" #展示上一行代码运行结果,即30