shell编程:
shell的概念介绍:
1.1命令解释器:
shell是命令解释器(command interpreter),是Unix操作系统的用户接口,程序从用户接口得到的输入信息,shell将用户程序及其输入翻译成操作系统内核(kernel)能够识别的指令,并且操作系统内核执行完将返回的输出通过shell在呈现给用户,下图所示用户,shell,和操作系统之间的关系
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L8Ujhb0I-1624872441787)(C:\Users\16326\Desktop\dayHomework\QQ截图20210624213540.png)]
(一个系统可以存在多个shell)
操作系统内核(kernal)与shell是独立的套件,而且都可以被替换;不同的操作系统使用不同的shell;同一个kernal之上可以使用不同的shell,也可以查看当前的shell是哪种:
Shell脚本:
Shell也是一门编程语言,即Shell脚本,在此脚本中,我们可以使用一些编程语法来进行一些任务操作,如:变量,类型,分支结构,循环结构,数组,函数等语法,在shell脚本中,必须指定一种shell命令解释器
Shell编程规范:
1.脚本文件的结构:
1.文件的扩展名必须是.sh
2.文件的首行必须是#! 指定script的运行shell环境(即脚本解释器)
例如:#!/bin/bash
3.脚本里的行注释符号为#
4.指令,选项,参数之间即使有多个空格仍然会被视为一个空格
5.tab键形成的空白也视为一个空格键
6.空白行会被忽略
2.脚本文件的执行;
1.使用bash程序调用执行,只需要有读权限即可
2.直接写script,必须要有rx权限才行
3.借助变量Path功能
3.Shell的变量:
3.1变量的用法:
1.变量的命名规则:
-命令只能使用英文字母,数字,下划线,首个字符不能以数字开头
-字母习惯使用大写
-中间不能有空格
-不能使用标点符号
-不能使用bash里的关键字,可以使用help命令查看保留关键字
2.变量的使用规则:
-直接定义变量名称,没有类型需要强调(类似于数学中:x=1,y=2,z=x+y)
-赋值时,“=”前后不能有空格
-命令的执行结果赋值给变量时,使用反单引号 如time=`date`
-调用变量时,必须使用$ 格式:$变量名 或者 ${变量名}
3.2变量的分类:
Linux Shell中的变量可以分为三种变量:局部变量,环境变量,特殊变量,可以通过set命令查看系统中存在的所有变量
局部变量:也就是用户自定义的变量,在脚本中或者命令行中定义
环境变量:保存和系统操作环境相关的数据,$HOME,$PWD,$SHELL,$USER等
特殊变量:
一种是位置参数变量:主要用来向脚本中传递参数或者数据,变量名不能自定义,变量作用固定
一种是预定义变量:是bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的
3.3局部变量:
用户自定义的变量由字母或者下划线开头,有字母,数字,下划线组成,并且大小写字母意义不同,变量名长度没有限制
1.定义变量:习惯上用大写字母来命名变量,变量名以字母表示的字符开头,不能用数字
2.调用变量:
2.1在使用变量的时候,要在变量名前加上前缀"$"
2.2使用echo,命令查看变量值
3.变量赋值:
第一种:定义时赋值:
#变量=值
#注意:在上述的定义方式中,等号两边不能有空格
[root@qianfeng01 ~]# str="hello qianfeng"
[root@qianfeng01 ~]# a=9
[root@qianfeng01 ~]# echo $a
9
[root@qianfeng01 ~]# echo $str
hello qianfeng
[root@qianfeng01 ~]# a=10
[root@qianfeng01 ~]# echo $a
10
第二种:将第一个命令的执行结果给变量赋值
[root@qianfeng01 ~]# A=`ll -a` --->反引号,运行里面的命令,并且把结果返回给变量A
[root@qianfeng01 ~]# echo $A
总用量 32 dr-xr-x---. 4 root root 159 6月 24 19:02 . dr-xr-xr-x. 17 root root 224 6月 24 15:30 .. -rw-------. 1 root root 1521 6月 22 18:55 anaconda-ks.cfg -rw-------. 1 root root 4691 6月 24 22:51 .bash_history -rw-r--r--. 1 root root 18 12月 29 2013 .bash_logout -rw-r--r--. 1 root root 176 12月 29 2013 .bash_profile -rw-r--r--. 1 root root 176 12月 29 2013 .bashrc -rw-r--r--. 1 root root 100 12月 29 2013 .cshrc drwxr-----. 3 root root 19 6月 24 19:02 .pki drwx------. 2 root root 57 6月 24 16:54 .ssh -rw-r--r--. 1 root root 129 12月 29 2013 .tcshrc
-------------------------------------------------------------------------------------
[root@qianfeng01 ~]# B=$(ll -a) --->等价于反引号
[root@qianfeng01 ~]# echo $B
总用量 32 dr-xr-x---. 4 root root 159 6月 24 19:02 . dr-xr-xr-x. 17 root root 224 6月 24 15:30 .. -rw-------. 1 root root 1521 6月 22 18:55 anaconda-ks.cfg -rw-------. 1 root root 4691 6月 24 22:51 .bash_history -rw-r--r--. 1 root root 18 12月 29 2013 .bash_logout -rw-r--r--. 1 root root 176 12月 29 2013 .bash_profile -rw-r--r--. 1 root root 176 12月 29 2013 .bashrc -rw-r--r--. 1 root root 100 12月 29 2013 .cshrc drwxr-----. 3 root root 19 6月 24 19:02 .pki drwx------. 2 root root 57 6月 24 16:54 .ssh -rw-r--r--. 1 root root 129 12月 29 2013 .tcshrc
-------------------------------------------------------------------------------------
[root@qianfeng01 ~]# aa=$((4+5))
[root@qianfeng01 ~]# echo $aa
9
-------------------------------------------------------------------------------------
[root@qianfeng01 ~]# bb=`expr 4+5`
[root@qianfeng01 ~]# echo $bb
4+5
[root@qianfeng01 ~]# bb=`expr 4 + 5`
[root@qianfeng01 ~]# echo $bb
9
第三种:将一个变量的值赋给另一个变量:
[root@qianfeng01 ~]# echo $a
hello world
4.变量叠加
#变量叠加,就是将两个字符串变量的值叠加在一起,类似于Java中的字符串拼接操作
[root@qianfeng01 ~]# a=123
[root@qianfeng01 ~]# echo $a
123
[root@qianfeng01 ~]# b="$a"456
[root@qianfeng01 ~]# echo $b
123456
[root@qianfeng01 ~]# e=${a}456
[root@qianfeng01 ~]# echo $e
123456
------------------------------------------------------------------------------------
#单引号和双引号的区别:
#现象:单引号里的内容会全部输出,而双引号里的内容会有变化
#原因:单引号会将所有的特殊字符脱意
[root@qianfeng01 ~]# num=10
[root@qianfeng01 ~]# sum="$num hehe"
[root@qianfeng01 ~]# echo $sum
10 hehe
[root@qianfeng01 ~]# sum2='$num hehe'
[root@qianfeng01 ~]# echo $sum2
$num hehe
删除变量:
#删除之前已经定义过了的变量,之后就无法再使用这个变量了
#撤销变量a
[root@qianfeng01 ~]# unset a
#声明静态的变量 b=2,不能使用unset
[root@qianfeng01 ~]# readonly b=2
[root@qianfeng01 ~]# unset b
-bash: unset: b: 无法反设定: 只读 variable
注意事项:
关于局部变量的作用域问题,用户自定义的局部变量,作用仅限于当前的shell环境,仅在当前的shell示例中有效,其他shell启动的程序不能访问局部变量
[root@qianfeng01 bin]# echo '#!bin/bash' > test.sh
[root@qianfeng01 bin]# a=22
[root@qianfeng01 bin]# echo $a
22
[root@qianfeng01 bin]# echo 'echo $A' >> test.sh
[root@qianfeng01 bin]# echo $a
22
[root@qianfeng01 bin]# bash test.sh
#打印结果为空,因为bash会开启一个新的shell进程
环境变量:
用户自定义的局部变量,只能在当前的shell和其所有的子shell中生效,如果把环境变量写进相应的配置文件,那么这个环境变量就会在所有的shell中生效
作用域:当前的shell以及所有的子shell
声明变量:export 变量名=变量值
定义环境变量的常见配置文件:
1./etc/profile ----> 针对系统所有的用户生效,此文件应用于所有用户每次登录系统时的环境变量定义,每次用户登陆的时候,都会加载这个文件
2. H O M E / . b a s h p r o f i l e − − − − − > 针 对 于 特 殊 的 用 户 生 效 , HOME/.bash_profile ----->针对于特殊的用户生效, HOME/.bashprofile−−−−−>针对于特殊的用户生效,HOME为用户的宿主目录,当这个用户登录的时候,首先加载/etc/profile文件中的定义,再加载$HOME/.bash_profile文件中的定义
位置参数变量:
变量 | 描述 |
---|---|
$n | n为数字表示第几个参数,$0表示命令本身,$1- 9 表 示 第 1 到 第 9 个 参 数 , 10 以 上 的 参 数 需 要 使 用 大 括 号 包 含 , 例 如 9表示第1到第9个参数,10以上的参数需要使用大括号{}包含,例如 9表示第1到第9个参数,10以上的参数需要使用大括号包含,例如{10} |
$* | 代表命令行中的所有参数,把所有参数看成一个整体,以“$1 2... 2... 2...n”的形式输出所有参数 |
$@ | 代表命令行中的所有参数,把每个参数区别对待,以"$1"" 2 " . . . . " 2"...." 2"...."n"的形式输出所有参数 |
$# | 参数的个数 |
@ 和 @和 @和*的区别:
1.他们都表示传递给函数或者脚本的所有参数,不被双引号包含时,都以"$1"" 2 " . . . " 2"..." 2"..."n"的形式输出所有参数
2.当他们被双引号包含时
2.1.“$*”会将所有的参数作为一个整体,以$1 $2 … $n的形式输出所有参数
2.2“$@”会将各个参数分开,以"$1"" 2 " . . . " 2"..." 2"..."n"的形式输出所有参数
预定义变量:
变量 | 描述 |
---|---|
$? | 执行上一个命令的返回值,执行成功,返回0;执行失败,返回非0 |
$$ | 当前进程的进程号(PID),即当前脚本执行时生成的进程号 |
$! | 后台运行的最后一个进程的进程号(PID),最后一个被放入后台执行的进程 |
read命令:
说明:
read命令,可以从控制台读取用户输入的内容,并且给指定的变量进行赋值
命令的基本格式为:read [option] variable
常用option:
-p:提示语句,在输入之前给用户提示信息
-n:显示输入的字符数量,到达这个数量的字符的时候,会自动地停止输入
-t:等待时间,单位为秒,当到达这个等待时间的时候,会自动地结束输入,并且不会读取任何输入的内容!
即,输入操作且回车,必须在执行的时间内完成
-s:隐藏输入的内容,在控制台上不显示任何输入的内容,常见于密码输入
注意事项:
1.在输入的时候,如果输入错了需要删除的时候,请使用ctrl+delete
2.符号不要输入中文
3.变量与之前的内容需要保持有空格
运算:
1.expr:
格式:expr m + n 或者 $((m+n)) 注意expr与运算符和变量之间要有空格
sum=$((m+n)) 中=与$之间没有空格
expr命令:对整数型变量进行算术运算
(注意:运算符前后必须要有空格)
[root@qianfeng01 ~]# expr 3 + 5
8
[root@qianfeng01 ~]# expr 3 - 5
-2
[root@qianfeng01 ~]# expr 3 / 5
0
[root@qianfeng01 ~]# expr 3 % 5
3
[root@qianfeng01 ~]# expr 3 \* 5 ------>*具有特殊含义,代表任意字符,所以需要使用转义字符\
15
[root@qianfeng01 ~]# echo $((3+5))
8
[root@qianfeng01 ~]# echo $((3-5))
-2
[root@qianfeng01 ~]# echo $((3/5))
0
[root@qianfeng01 ~]# echo $((3%5))
3
[root@qianfeng01 ~]# echo $((3*5))
15
2. ( ) 与 ()与 ()与{}的区别
$()的用途和反引号``一样,用来表示优先执行的命令
[root@qianfeng01 ~]# echo $(ls /root)
anaconda-ks.cfg
${}作用是用来取变量
echo ${PATH}
$((运算内容)) 用于数字运算
字符串
1.字符串的脚本用法:
字符串不能单独使用,必须要配合变量
字符串可以使用单引号[' '],也可以使用双引号[" "],也可以不使用引号
单引号内的任意字符没有任何意义,都回原样输出
单引号内使用变量是无效的,单引号内不能出现单引号
双引号内可以使用变量
双引号内可以使用转义字符
在字符串拼接操作的时候我们可以进行无缝拼接,或者是在双引号里使用变量
2.字符串的长度
可以使用${#variable}或者expr length "${variable}"
示例:
#!/bin/bash
var='welcome to China'
length1=${#var}
length2=$(expr length "${var}")
length3=`expr length "$var"`
echo $length1
echo $length2
echo $length3
shell数组:
1.数组的使用规则:
在/bin/bash这个shell中,只有一维数组的概念,并且不限制数组的长度
数组的元素是从0开始的
获取数组的元素要使用下标
下标使用不当,会报错
2.数组的定义:
定义格式:variable=(值1,值2,... 值3)
注意:元素之间除了使用空格作为分隔符,还可以使用换行符
或者
name[0]=值1
name[1]=值2
...
name[n]=值n
3.读取数组:
${variable[index]} 读取index索引上的元素
${variable[*]} 读取所有元素
${#variable[*]}或者${#variable[@]} 获取数组的长度
[root@qianfeng01 ~]# cat test3.sh
#!/bin/bash
citys=(chen heng wen tian yuan)
hobby[0]=read
hobby[1]=film
hobby[2]=music
echo ${citys[0]}
echo ${hobby[*]}
echo ${#hobby[@]}
[root@qianfeng01 ~]# bash test3.sh
chen
read film music
3
test测试命令:
文件检测类型:
test -e filename | 检测filename是否存在 |
---|---|
test -d filename | 检测filename是不是目录 |
test -f filename | 检测filename是不是普通文件 |
test -L filename | 检测filename是不是软链接文件 |
文件属性检测:
test -r filename | 检测filename是否有可读权限 |
---|---|
test -w filename | 检测filename是否有可写权限 |
test -x filename | 检测filename是否有执行权限 |
两个文件的比较:
test file1 -nt file2 | 检测file1是否比file2新 |
---|---|
test file1 -ot file2 | 检测file1是否比file2旧 |
test file1 -ef file2 | 检测file1和file2是否为同一文件 |
两个整数进行比较:
test n1 -eq n2 | 检测n1与n2是否相等 |
---|---|
test n1 -ne n2 | 检测n1与n2是否不等 |
test n1 -gt n2 | 检测n1是否大于n2(greater than) |
test n1 -lt n2 | 检测n1是否小于n2(less than) |
test n1 -ge n2 | 检测n1是否大于等于n2 |
test n1 -le n2 | 检测n1是否小于等于n2 |
里那个字符串进行比较:
test -z string | 检测string是否为空 |
---|---|
test -n string | 检测string是否不为空 -n 可以省略 |
test string1 == string2 | 检测string1与string2是否相等 |
test string1 != string2 | 检测string1与string2是否不相等 |
多条件连接:
test -r filename -a -x filename | and,两个检测都成立,返回true |
---|---|
test -r filename -o -x filename | or,只要有一个成立,就返回true |
test ! r filename | 非 |
1.通常来说test命令不单独使用,而是与if语句连用,或者是放在循环结构中
2.判断符号[]
除了好用的test之外,我们还可以使用中括号来进行检测条件是否成立
条件控制:
if条件语句-单分支
if [条件判断]
then
条件成功时执行逻辑
fi
if [条件判断];then
条件成立时的逻辑
fi
#!/bin/bash
a=$1
if($a == "true")
then
echo "hello world"
fi
注意事项:
1.if语句需要使用fi结尾,和一般的语言使用大括号结尾不同
2.[条件判断] 就是用test命令进行判断,所以中括号和条件判断之间必须要有空格
3.then后面跟符合条件之后执行的程序,可以放在[]之后,用;分隔,也可以换行写入,就不需要;了
4.if与中括号之间必须要有空格
if条件语句-多分支
if [条件判断1]
then
当条件判断1成立之时,执行程序1
elif [条件判断2]
then
当条件判断式2成立之时,执行程序2
else
当所有条件都不满足时,执行此程序
fi
示例:
编写⼀个坐⻋脚本,要求:
脚本名字: home.sh
逻辑: 从外⾯传⼊⼀个参数,根据参数判断: 1. 坐⻜机,2. 坐⽕⻋,3. 坐⽕箭,4.
不回了
[root@qianfeng01 myShell]# cat test6.sh
#!/bin/bash
read -p "please input your choice:" choice
if [ $choice == 1 ] #当然也可以使用test,括号中的内容换成 $choice -eq 1
then
echo "坐飞机"
elif [ $choice == 2 ]
then
echo "坐火车"
elif [ $choice == 3 ]
then
echo "坐火箭"
else
echo "不回了"
fi
case:
在java中我们学过了switch-case这种结构,这种结构, 我们可以捕获一个变量的值,对这个变量取到的某些值进行不同的处理,在Shell中 ,也有类似的结构,就是case
case命令是一个多分支的if/else命令,case变量的值用来匹配value1,value2,value3等不同的值
-匹配到之后,执行后面的命令,直到遇到双分号为止
-类似于if命令,case命令使用esac作为终止符
-case行尾必须为单词in
-每个分支必须以右括号结束
-匹配模式中可以使用方括号表示一个连续的范围,如[0-9];使用“|”表示或
#case的格式
CMD=$1
case $CMD in
-------case行尾必须为 变量 in 表示捕获这个变量的值
start)
-------需要匹配到的值,需要以右括号作为结尾
echo "starting"
匹配到之后,执行的逻辑语句,即一个分支
;;
--------一个分支的逻辑,需要以;;作为结束,不会向下穿透
stop)
echo "stopping"
;;
*)
---------*表示以上的分支都不满足的情况,类似于switch-case中的default
echo "please using start|stop"
;;
esac
---------case语句,需要使用esac结束
#!/bin/bash
case $1 in
"1")
echo "周一"
;;
"2")
echo "周二"
;;
"3")
echo "周三"
;;
"4")
echo "周四"
;;
"5")
echo "周五"
;;
"6")
echo "周六"
;;
"7")
echo "周日"
;;
esac
循环:
for循环:
for循环命令用来在一个列表条目中执行有限次数的命令
比如:你可能会在一个姓名列表或者文件列表中循环执行同一个命令
for命令后紧跟着一个自定义变量,一个关键字in和一个字符串列表(可以是变量)
第一次执行for循环的时候,字符串列表的第一个字符串会赋值给自定义变量,然后执行循环命令,直到遇到done语句;
第二次执行for循环的时候,会右推字符串列表中的第二个字符串给自定义变量
以此类推,知道字符串列表遍历完
方式一:
for N in 1 2 3
do
echo $N
done
--------------------------------------------------------------------------------
for N in 1 2 3 ;
do
echo $N;
done
--------------------------------------------------------------------------------
for N in {1..3};
do
echo $N;
done
--------------------------------------------------------------------------------
for N in {1,2,3};
do
echo $N;
done
方式二:
for((i = 0; i <= 5; i++))
do
echo $i
done
--------------------------------------------------------------------------------
for((i = 0; i <= 5; i++));
do
echo $i ;
done
while循环:
while命令根据紧跟其后的命令(command)来判断是否执行while循环,当command执行后的返回值(exit status)为0时,则执行while循环语句块,直到遇到done语句,然后再返回到while命令,判断command的返回值,当得到返回值为非0时,则终止while循环
第一种:
while [ expression ]
do
command
done
第二种:
while((expression))
do
command
...
done
函数:
1.函数代表着一个或者一组命令的集合,表示一个功能模块,常用于模块化编程
2.以下是关于函数的一些重要说明:
在Shell中,函数必须先定义,再调用
使用return value来获取函数的返回值
函数在当前shell中执行,可以使用脚本中的变量
函数名()
{
命令一
命令二
return 返回值变量
}
结构:
[ function ] funname [ () ]
{
action;
[return int;]
}
function start() / function start / start()
注意事项:
如果返回值后面没有(),在函数名和{之间,必须要有空格以示区分。
函数返回值,只能通过$?,系统变量获取,可以显示加:return 返回值
如果不加return 将以最后一条命令的运行结果作为返回值
return后面的内容以字符串的形式写入,但是执行时会自动转换成数值类型,范围:数值n[0-255]
脚本测试:
-x:执行脚本,并显示所有变量的值
-n:不执行脚本,只是检查语法,将返回所有语法错误,例如函数没有正确闭合等
-v:执行并显示脚本内容
on ]
do
command
done
第二种:
```shell
while((expression))
do
command
...
done
函数:
1.函数代表着一个或者一组命令的集合,表示一个功能模块,常用于模块化编程
2.以下是关于函数的一些重要说明:
在Shell中,函数必须先定义,再调用
使用return value来获取函数的返回值
函数在当前shell中执行,可以使用脚本中的变量
函数名()
{
命令一
命令二
return 返回值变量
}
结构:
[ function ] funname [ () ]
{
action;
[return int;]
}
function start() / function start / start()
注意事项:
如果返回值后面没有(),在函数名和{之间,必须要有空格以示区分。
函数返回值,只能通过$?,系统变量获取,可以显示加:return 返回值
如果不加return 将以最后一条命令的运行结果作为返回值
return后面的内容以字符串的形式写入,但是执行时会自动转换成数值类型,范围:数值n[0-255]
脚本测试:
-x:执行脚本,并显示所有变量的值
-n:不执行脚本,只是检查语法,将返回所有语法错误,例如函数没有正确闭合等
-v:执行并显示脚本内容