一、shell 的概述
1.脚本语言与 C/C++的区别
- 对比:
- C/C++是编译型语言:编写好的代码需要经过预处理、编译、汇编、链接生成可执行文件,运行可执行文件得到进程,是静态语言;
- 脚本语言:编写代码,脚本解析器逐行分析执行,脚本语言对代码的格式要求高,要严格按照其语法要求编写,有时候多一个空格都不行,是动态语言。
2.shell 的介绍
shell 既是应用程序(shell 解析器),又是程序设计语言(shell 脚本语言)。
常见的 shell 解析器有:sh、ash、bash
- 通过命令查看默认解析器
edu@edu:~$ echo $SHELL
/bin/bash # 解析器
edu@edu:~$ env # 查看系统环境变量
XDG_SESSION_ID=1
TERM=xterm
SHELL=/bin/bash
SSH_CLIENT=192.168.1.5 50316 22
SSH_TTY=/dev/pts/23
USER=edu
......
- 说明:
- 当前系统默认的解析器是 bash 解析器;
- shell 里面查看某个变量的值,需要在变量名前加 $ 美元符号;
- env 命令用于查看系统的环境变量;
- shell 脚本是用户操作内核数据的途径之一;
- 可以通过 shell 脚本完成批处理,完成大量重复执行的动作。
3.Linux 自动调用的脚本
linux 自动调用/etc/profile
和 ~/.bashrc
两个脚本,这两个文件都是用来配置配置环境的。
/etc/profile
用户登录的时候自动调用该文件,用于配置系统的环境,即修改环境变量的话,当前系统所有用户的配置都会发生改变;~/.bashrc
用户登录、用户打开终端时自动调用该文件,用于配置用户环境变量,即只在当前用户有效。
二、shell 语法
1.第一个 shell 脚本
- 代码演示
#!/bin/bash
# 打印一句话
echo "hello world"
- 说明:
- #!表示指明解析器为 bash 解析器;
#
后面跟注释;- 通过 vim 创建的文件没有可执行权限,需要通过
chmod +x 文件名
为其添加可执行权限;
edu@edu:~/study/my_code$ ls 01-first_code.sh -lh # 查看脚本文件权限
-rw-rw-r-- 1 edu edu 50 12月 28 15:46 01-first_code.sh # 没有 x 可执行权限
edu@edu:~/study/my_code$ chmod +x 01-first_code.sh # 添加可执行权限
edu@edu:~/study/my_code$ ls 01-first_code.sh -lh
-rwxrwxr-x 1 edu edu 50 12月 28 15:46 01-first_code.sh
edu@edu:~/study/my_code$ ./01-first_code.sh # 执行脚本
hello world # 运行结果
多行注释可以用:
<<COMMENT
要注释的多行代码
COMMENT
2.运行脚本的三种方法
./脚本文件
:先使用文件中 #! 指定的解析器解析,如果该解析器不存在 使用系统默认的解析器解析,是当前 shell 开启一个子 shell来执行,不会影响当前 shell 的配置;bash 脚本文件
:先直接使用 bash 解析器解析,如果 bash 解析器不存在,再使用系统默认的解析器,是当前 shell 开启一个子 shell来执行,不会影响当前 shell 的配置;. 脚本文件
:直接使用系统默认的解析器解析,在当前 shell 执行,如果需要脚本修改当前 shell 的环境配置,选用这种方法运行。
3.shell 的变量
3.1变量的定义及读取
- 代码演示
#!/bin/bash
# 定义一个变量
num=100
echo "num = $num" # 100
- 运行结果
num = 100
data = 100
- 说明:
- 赋值的时候等号两边不能有空格;
- shell 脚本的变量没有类型;
- 取变量的值等读操作的时候,变量的左边要加美元符号$。
3.2 unset 清除一个变量
如果某个已经定义的变量我们不想用了,可以将其清除掉。
- 代码演示
num=100
echo "num = $num"
unset num
echo "num = $num"
- 运行结果
num = 100
num =
- 说明:可以看到,访问被清除的变量访问的是空。
3.3变量获取键盘输入
- 第一种方法:
read 变量名
echo "请输入一个整数:"
read num1
echo "num1 = $num1"
- 运行结果
请输入一个整数:
55
num1 = 55
-
说明:这种方法虽然能够获取,但可以看到提示信息和输入不在同一行,不够美观。
-
第二种较美观的方法:
read -p "提示信息" 变量名
# 为一个变量值获取
read -p "请输入一个整数:" num
echo "num = $num"
# 为多个变量值获取
read -p "请输入两个整数:" num1 num2
echo "num1 = $num1, num2 = $num2"
- 运行结果
请输入一个整数:100
num = 100
请输入两个整数:100 200
num1 = 100, num2 = 200
-
说明:
- 注意 -p 要在 read 之后,提示信息之前;
- 当为多个变量获取输入的时候,变量名之间有空格隔开。
-
获取带空格的字符串
# 错误的方式
read -p "请输入一个字符串:" str1 str2
echo "str1 = $str1, str2 = $str2"
# 正确的方式
read -p "请输入一个字符串:" str
echo "str = $str"
- 运行结果
请输入一个字符串:hello world my name is jack
str1 = hello, str2 = world my name is jack
请输入一个字符串:hello world my name is jack
str = hello world my name is jack
- 说明:
- 从第一个案例可以看出,第一个变量在遇到空格后就结束获取了,但第二个即最后一个变量会获取剩余的使用,包括空格;
- 要键盘获取带空格的字符串,只能一次对一个变量操作。
3.4只读变量
- 只读变量:在定义变量的时候在前面加上 readonly 修饰
readonly num=10
echo "num = $num"
num=20
echo "num = $num"
- 运行结果
num = 10
./02-shell变量.sh: 行 35: num: 只读变量 # 提示信息,不可修改
num = 10
3.5导出环境变量
环境变量:是操作系统自动识别的变量,通过 evn 命令可以查看系统环境变量,前面有演示。
导出环境变量:就是将自定义变量存放在 env 中,使其成为系统的环境变量。
- 通过
export 自定义变量
导入环境变量
# 导入环境变量
export DATA=10086
- 终端运行的时候需要通过:
source 脚本文件
运行才能在当前 shell 导入环境变量
edu@edu:~/study/my_code$ source 02-shell变量.sh
edu@edu:~/study/my_code$ echo $DATA # 终端命令查看系统环境变量
10086
3.6单引号和双引号的区别
- 代码演示
num=10
echo "num = $num"
echo 'num = $num'
- 运行结果
num = 10
num = $num
- 说明:
- 双引号会解析出变量的值;
- 单引号会将其当成字符串处理。
3.7预设变量
-
常用的预设变量
-
$#:传给 shell 脚本参数的个数,即调用脚本的时候后面跟的参数个数;
-
$*:传给 shell 脚本参数的内容,这里是全部内容;
-
$1、$2、$3、…、$9:运行脚本时传递给其的参数,访问时用空格隔开;
-
$?:命令执行后返回的状态 ,用于检查上一个命令执行是否正确(在 Linux 中,状态为 0 表示该命令正确执行,任何非 0 值表示命令出错);
-
$0:当前执行的进程名;
-
$$:当前进程的进程号 ,最常用作临时文件的名字以保证临时文件不会重复。
-
代码演示
echo "参数的个数:$#"
echo "所有参数:$*"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "第三个参数:$3"
echo "上一条命令执行的状态:$?"
echo "当前进程名:$0"
echo "当前进程号:$$"
ls # 脚本文件里输入命令
- 运行结果
edu@edu:~/study/my_code$ ./02-shell变量.sh aa bb cc
参数的个数:3
所有参数:aa bb cc
第一个参数:aa
第二个参数:bb
第三个参数:cc
上一条命令执行的状态:0
当前进程名:./02-shell变量.sh
当前进程号:7739
01-first_code.sh 02-shell变量.sh # 命令同样执行将结果输出到终端
3.8变量的特殊用法
双引号和单引号上面已经介绍过了
- 反引号里面写系统命令,会将命令执行的结果赋值给变量:
fileList=`ls`
echo "$fileList"
- 运行结果
edu@edu:~/study/my_code$ source 02-shell变量.sh
01-first_code.sh
02-shell变量.sh
- 转义字符:同C语言,但正常情况下转义字符不生效,需要加 -e 选项
echo "hello\nworld"
echo -e "hello\nworld" # -e 加在 echo 后,字符串前
- 运行结果
hello\nworld
hello
world
- 子 shell ,(命令序列)即将要完成的内容通过创建一个子 shell 来完成
num=100
(
num=200
echo "num = $num"
)
echo "num = $num"
- 运行结果
num = 200
num = 100 # 没有影响到当前 shell 的值
-
运行效果类似于C语言里面的局部变量和全局变量同名的现象,其实小括号里是当前 shell 创建的一个子 shell,为了避免运行对当前 shell 环境产生影响,放到子 shell 运行。
-
当前 shell ,{ 命令序列 },强调在当前 shell 种执行,会影响到当前 shell,注意:中括号两边空格
num=100
{
num=200
echo "num = $num"
}
echo "num = $num"
- 运行结果
num = 200
num = 200 # 对当前 shell 的值做出了修改
三、条件测试语句
1.测试语句语法
- 语法
test 条件语句
[ 条件语句 ] #[]有空格
测试包括:对文件测试、字符串测试、数字测试、复合测试,测试语句一般与条件语句联合使用。
2.文件测试
对文件的测试包含以下几个方面的测试:
-e 测试存在
-d 测试是目录
-f 测试是文件
-r 文件可读
-w 文件可写
-x 文件可执行
-L 符号连接
-c 是否字符设备
-b 是否块设备
-s 文件非空
# 上面条件满足,运行状态为0,否则非0
- 代码演示
fileName="a.txt"
ls -lh "a.txt" # 查看文件的详细信息用于结果对比
test -e $fileName
# 查看上条语句执行的结果
echo $?
test -d $fileName
echo $?
test -f $fileName
echo $?
[ -r $fileName ]
echo $?
[ -w $fileName ]
echo $?
[ -x $fileName ]
echo $?
[ -s $fileName ]
echo $?
- 运行结果
-rw-rw-r-- 1 edu edu 0 12月 28 20:18 a.txt
0 # 文件存在
1 # 不是目录
0 # 是文件
0 # 可读
0 # 可写
1 # 不可执行
1 # 文件为空
3.字符串测试
3.1基础语法
- 语法
test stroperator “str”
test “str1” stroperator “str2”
[ stroperator “str” ]
[ “str1” stroperator “str2”]
-
说明:
stroperator
:是用于字符串判断的操作符,或选项。包括 := 两个字符串相等, != 两个字符串不相等, -z 空串, -n 非空串;- []两边记得加空格;
-
代码演示
str1=hello
str2=hello
str3=hallo
test -z $str1
echo $?
[ -n $str1 ]
echo $?
test $str1 = $str2
echo $?
[ $str1 = $str3 ]
echo $?
- 运行结果
1 # 不为空
0 # 非空
0 # 相等
1 # 不相等
- 说明:
- 在比较过程中是比较变量对应的值,而不是变量名,因此要先读到变量的值,就需要加 $;
- 判断是否相等的时候等号两边加空格。
3.2扩展语法
- 代码演示
str=aaa:bbb:cc:dddd
# 求字符串的长度
echo ${#str}
# 从第 n 个字符取字符串
echo ${str:3}
# 从第 n 个字符取字符串,取指定个数
echo ${str:3:5}
# 从左往右替换指定第一个字符
echo ${str/:/*}
# 从左往右替换指定的所有字符
echo ${str//:/*}
- 运行结果
15
:bbb:cc:dddd
:bbb:
aaa*bbb:cc:dddd
aaa*bbb*cc*dddd
4.数值测试
4.1基础语法
- 语法
test num1 numoperator num2
[ num1 numoperator num2 ]
numoperator可选参数为:
-eq 数值相等
-ne 数值不相等
-gt 左数 大于 右数
-ge 左数 大于等于 右数
-le 左数 小于等于 右数
-lt 左数 小于 右数
满足,表达式的状态为0,否则非0
- 代码演示
num1=10
num2=20
test $num1 -eq $num2
echo $?
test $num1 -ne $num2
echo $?
[ $num1 -gt $num2 ]
echo $?
[ $num1 -lt $num2 ]
echo $?
- 运行结果:
1 # 不相等
0 # 不相等
1 # 不大于
0 # 小于
4.2扩展语法
- 代码演示
echo ${data:-100}
data=200
echo ${data:-100}
echo ${data1:=300}
echo $data1
- 运行结果
100
200
300
300
- 说明:
echo ${data:-100}
:当 data 存在时,表达式的结果就是 data 的值,不存在的时候,表达式的结果就是100;echo ${data1:=300}
:当 data1 存在时,表达式的结果就是 data1 的值,不存在时,表达式的结果就是300,并且还会创建一个变量 data1 将其赋值为300。
5.符合测试
符合测试类似于C语言中的逻辑与、逻辑或。
5.1单条件判断
command1 && command2
&& 左边命令执行成功,shell 才执行 && 右边的命令;
command1 || command2
|| 左边的命令未执行成功,shell 才执行 || 右边的命令。
- 案例:键盘输入一个数,判断是否在 0 ~ 100 之间
read -p "请输入一个数:" num
test $num -gt 0 && test $num -lt 100
echo $?
[ $num -gt 0 ] && [ $num -lt 100 ]
echo $?
- 运行结果
请输入一个数:50
0
0
edu@edu:~/study/my_code$ ./02-shell变量.sh
请输入一个数:120
1
1
5.2多重条件判断
- -a :两种状态同时成立;
- -o :两种状态成立一个;
- !:相反状态。
- 上面的案例,通过多重条件判断实现
read -p "请输入一个数:" num
test $num -gt 0 -a $num -lt 100
echo $?
[ $num -gt 0 -a $num -lt 100 ]
echo $?
- 运行结果
请输入一个数:150
1
1
edu@edu:~/study/my_code$ ./02-shell变量.sh
请输入一个数:50
0
0
6.if 条件语句
6.1if 语句的三种形式
1.单条件语句
if [ 条件1 ];then
语句1
fi
2.双条件语句
if [ 条件1 ];then
语句1
else
语句2
fi
3.多条件语句
if [ 条件1 ];then
语句1
elif [ 条件2 ];then
语句2
else
语句3
fi
- 说明:
[ 条件1 ]
就是我们上面学习的测试语句,记得中括号两侧加空格。
6.2if 语句案例
- 案例:键盘输入文件名,判断当前目录是否有此文件,如果有请输出文件内容,如果没有,创建此文件,并键盘输入文件内容写入文件,并输出内容。
read -p "请输入文件名:" fileName
# 判断文件是否存在且非空
if [ -e $fileName -a -s $fileName ];then
cat $fileName
else
touch $fileName
read -p "请输入内容:" content
# 将临时变量的值输入到文件
echo $content >> $fileName
cat $fileName
fi
- 运行结果
edu@edu:~/study/my_code$ ls
01-first_code.sh 02-shell变量.sh a.txt
edu@edu:~/study/my_code$ ./02-shell变量.sh
请输入文件名:a.txt
hello a.txt
edu@edu:~/study/my_code$ ./02-shell变量.sh
请输入文件名:b.txt
请输入内容:hello b.txt
hello b.txt
7.case 语句
7.1case 语句语法
case $变量 in
值1)
语句 1
;;
值2)
语句 2
;;
*)
语句 3
;;
exit 1 #退出 shell
esac
- 说明:
- 这里的
值1)
相当于C语言中的case 值1
,*)
相当于 default; - ;; 相当于C语言中的 break。
- 这里的
7.2 case 案例
- 代码演示
read -p "请输入(hello 或 bye):" text
case $text in
h* | H*)
echo "你好"
;;
b* | B*)
echo "再见"
;;
esac
- 运行结果
请输入(hello 或 bye):hello
你好
edu@edu:~/study/my_code$ ./02-shell变量.sh
请输入(hello 或 bye):By
再见
- 说明:
h* | H*
中的 * 是通配符,可以匹配任意字符,这里是匹配任何以 h 或 H 开头的字符串。
四、循环语句
1.for 循环语句
1.1 for 循环的第一种格式
- 语法
for (( 初始值; 循环条件; 步进语句 ))
do
循环体
done
- 案例:计算 1 ~ 100 累加和
declare -i i=0
declare -i num=0
for (( i=1,num=0; i<=100; i++ ))
do
num=$num+$i
done
echo "计算结果num = $num"
- 运行结果
计算结果num = 5050
- 说明:
- 因为 shell 变量没有数据类型,因此需要通过
declare -i i=0
强制指定 i 为 int 类型的数据; - for 循环双小括号两侧留有空格。
- 因为 shell 变量没有数据类型,因此需要通过
1.2 for 循环的第二种格式
- 语法
for var in con1 con2 con3 ... con100
do
循环体
done
第 1 次循环的时候 var 的值为 con1
第 2 次循环的时候 var 的值为 con2
第 3 次循环的时候 var 的值为 con3
....
第 n 次循环的时候 var 的值为 conn
类似于 python 里面的 for 循环,for i in 可迭代对象
- 代码演示
for num in 1 2 3 4
do
echo "num = $num"
done
- 运行结果
num = 1
num = 2
num = 3
num = 4
1.3 for 循环案例
- 扫描当前目录,并且判断是文件还是目录
for file in `ls -a`
do
if [ -f $file ];then
echo "$file是文件"
elif [ -d $file ];then
echo "$file是目录"
fi
done
- 运行结果
.是目录
..是目录
01-first_code.sh是文件
02-shell变量.sh是文件
a.txt是文件
b.txt是文件
test是目录
2. while 循环
- 语法
while [ 循环条件 ]
do
循环语句
done
条件满足进入循环,不满足退出循环
- 计算 0 ~ 100 的累加和
declare -i i=1
declare -i num=0
while [ $i -le 100 ]
do
num=$num+$i
i=$i+1
done
echo "计算结果num = $num"
- 运行结果
计算结果num = 5050
- 说明:判断符号还有自增只能在 for 循环里面用, while 循环里面语法错误。
3. until 循环
- 语法
until [ 条件 ]
do
循环体
done
直到条件满足退出循环,否则一直循环到条件满足
- 计算 0 ~ 100 的累加和
declare -i i=1
declare -i num=0
until [ $i -gt 100 ]
do
num=$num+$i
i=$i+1
done
echo "计算结果num = $num"
- 运行结果
计算结果num = 5050
五、函数
1.函数定义格式
- 语法
格式一:
函数名()
{
函数体
}
格式二:(推荐)
function 函数名() # 函数没有形参,只在调用的时候传实参
{
函数体
}
2.函数调用格式
函数名 实参1 实参2 实参3 # 实参间用空格隔开
# 函数内部使用实参,结合前面学习的知识
$1==实参1
$2==实参2
$3==实参3
- 案例:定义一个函数,键盘获取输入,求两个数的和
declare -i num1
declare -i num2
function myAdd()
{
declare -i ret
ret=$1+$2
return $ret
}
read -p "请输入两个数:" num1 num2
myAdd $num1 $num2
echo "计算结果 = $?"
- 运行结果
请输入两个数:10 20
计算结果 = 30
- 涉及到多文件编程的时候,只需要在主脚本文件里面通过
source 脚本文件
包含其它脚本,就能使用其它脚本里面的函数了。