Shell程序设计语言

news/2025/1/14 19:23:44/文章来源:https://www.cnblogs.com/03270925yhd/p/18671425

Shell程序设计语言

一、认识Shell

1.1 编程语言的种类

# 机器语言:站在计算机(奴隶)的角度,说计算机能听懂的语言,那就是直接用二进制编程,直接操作硬件;优点:执行效率最高缺点:1、二进制指令难以记忆,开发时极容易出错2、开发程序的复杂度高:即便是完成一个简单的功能,需要用到的二进制指令的条数都会非常多
# 汇编语言:站在计算机(奴隶)的角度,简写的英文标识符取代二进制指令去编写程序,本质仍然是直接操作硬件;优点:解决了机器语言的二进制指令难以记忆的问题,执行效率还是高缺点:开发程序的复杂度依然很高:因为汇编语言就是用英文标签对应原来的二进制指令,好记归好记,开发的复杂度却没有降低ps:因为上述两类语言都是在直接与计算机硬件打交道,离计算机硬件比较近,所以又统称为低级语言
# 高级语言:站在人(奴隶主)的角度,说人话,即用人类的字符去编写程序,屏蔽了硬件操作优点:开发复杂度地,即开发效率高缺点:速度肯定是不如低级语言,一直到今天,对速度要求极高的场景还会用到低级语言,比如操作系统的调度程序

1.2 什么是Shell

# 1、一层指的是shell这门语言,是一种特定的语法风格,规范等# 2、另外一层指的是专门用于解释执行shell这门语言语法的应用程序,即shell解释器,我们常用的是bash

我们centOS7自带了Shell解释器,不需要额外安装

image-20240125172613655

一般情况下,我们创建的用户默认是/bin/bash

image-20240125172630605

shell 本身就是一门解释型、弱类型、动态语言,与 python 相对应, Python 属于解释型、强类型、动态语言,我们平时登录成功一个用户后进入的就是 bash 解释器的交互式环境,我们敲的命令其实都属于 shell 这门语言的语法

shell的优点

1. 自动备份
2. 自动部署
3. 监控脚本
4. 自动运行任务

1.3 第一个shell脚本

其实我们写shell脚本有两个地方可以写:1. 交互式环境(简单理解就是我们的linux窗口)2. 写到文件中(通常以.sh结尾)

交互式环境写脚本

image-20240125172636678

脚本文件

其实将我们在交互式环境里敲的命令直接放到一个文本文件里,一个简单的 shell 程序就完成了 
注意:shell 解释器执行程序是解释执行的,即打开文件内容,因此文件的后缀名没有硬性限制,但通常定义为.sh 结尾

image-20240125172642684

解释:

# 第一行表示我们选择使用的shell解释器是bash,也可以用:#!/usr/bin/env bashshell的第一行比较特殊,一般都会以#!开始来指定使用的shell解释的类型。在linux中,除了bash shell以外,还有很多版本的shell, 例如zsh、dash等等...不过bash shell还是我们使用最多的。
# 第二行以#号开始,表示本行是注释,注释是对代码的解释说明,注释的内容不会执行,对关键代码加注释是一种好的编程习惯
# 第三行中的echo是linux中的输出命令,该行的意思很明显的就是输出hello world!

1.4 shell脚本的运行方式

方式一:输入脚本的绝对路径或相对路径

/root/shujia.sh./shujia.sh# 注意:执行的必须是一个可执行文件  chmod a+x xxx.sh

方式二:bash或sh +脚本

sh helloworld.sh# 注意:当脚本没有X权限时,root和文件所有者通过该方式可以正常执行

方式三:在脚本的路径前再加"或source

source helloworld.sh

区别:

第一种和第二种会新开一个bash,不同bash中的变量无法共享。第三种是在同一个shell里面执行的# 一个shell环境就是一个单独的全局作用域,不同的shell环境,无法访问彼此shell环境中的变量
[root@master ~]$ x=99
[root@master ~]$ cat /a/b/hello.sh 
#!/bin/bashecho "hello world!"  
echo $x  # 我们在这里访问一下全局变量x[root@master ~]$ source /a/b/hello.sh  # 在当前shell环境执行,可以访问到x
hello world!
111         # 取到了x的值
[root@master ~]$ bash /a/b/hello.sh  # 在子shell环境执行,不能访问到x 
hello world!# 此处打印空

解决方案:export :可以将当前进程的变量传递给子进程去使用

注意:将来配置profile的时候所有的变量前必须加export

二、Shell编程语法

2.1 注释

  1. 可以加在被注释代码的正上方单独一行,或者被注释代码的正后方,例如

    echo "hello" # 注释。。。

  2. 不用全部加注释,只需要在自己觉得重要或不好理解的部分加注释即可

  3. 注释可以用中文或英文,但不要用拼音

分类:

单行注释:#
以 # 开头的行就是注释,会被解释器忽略。通过每一行加一个 # 号设置多行注释
多行注释 :<<
# 特殊的多行注释 
# end of file
:<<EOF  
注释内容... 
注释内容... 
注释内容... 
EOF:<<! 
注释内容... 
注释内容... 
注释内容... 
!

2.2 变量

借助java程序对变量的理解:变量就是程序运行过程中其值可以发生改变的量

语法定义格式

# 1、语法:变量名=值
# 2、注意:等号左右两边不能有空格!!!
# 3、例如:
[root@master soft]# name="xiaohu"

变量的引用

[root@master soft]# address="安徽合肥"
[root@master soft]# echo $address
安徽合肥注意:如果是打印百分比,建议使用${变量名}%
[root@master soft]# percent=90
[root@master soft]# echo ${percent}%
90%

删除变量

[root@master soft]# x=999
[root@master soft]# unset x
[root@master soft]# echo $x[root@master soft]# 

变量的命名规范

# 变量名的命令应该见名知意,同时遵循如下规则
以字母或下划线开头,剩下的部分可以是:字母、数字、下划线,最好遵循下述规范:1.以字母开头2.使用中划线或者下划线做单词的连接  shujia-xiaohu  shujia_xiaohu  3.同类型的用数字区分  shujia1  shujia24.对于文件名的命名最好在末尾加上拓展名  score_xiaohu.sh  score_shizhaoyang.sh例如: shujia_test.tar.gz 5、不要带有空格、?、*等特殊字符6、不能使用bash中的关键字,例如if,for,while,do等7、不要和系统环境变量冲突

变量的使用场景

场景一:直接赋值
# 1. 显式赋值:变量名=变量值
[root@master soft]# name2="xiaohu"
[root@master soft]# echo $name2
xiaohu
[root@master soft]# name2="xiaohua"
[root@master soft]# echo $name2
xiaohua
场景二:脚本运行传值
从调用脚本时传入的位置参数获取变量值:./a1.sh a1 a2 a3
需要用到$n获取第n个位置参数值,超过10需要用${n},如下
$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10}# 示例
[root@master soft]# cat a1.sh 
#!/bin/bash
echo ${0}
echo $1
echo $2
echo $3
echo $4
echo $5
echo $6
echo $7
echo $8
echo $9
echo ${10}
echo ${11}
echo ${12}
场景三:用户交互传值
何为交互,即输入、输出# 一:read接收用户的输入,即从键盘读入变量值
read 变量名
read -p "提示信息: "  变量名
read -t 5 -p "提示信息: "  变量名  # -t指定秒数
read -n 2 变量名  # -n读取的字符个数应用示例:vim name.sh
read -p "请输入你的姓名 " name
echo $name# 二:输出
# echo命令
[root@master soft]# name="xiaohu"
[root@master soft]# age=18
[root@master soft]# echo -e "my name is\t$name\nmy age is\t$age"
my name is  xiaohu
my age is   19还可以输出带颜色(了解即可)
# echo -e "\033[字背景颜色;文字颜色m字符串\033[0m"
# 例如
# echo -e "\033[47;30m I love shujia! \033[0m",其中47的位置代表背景色, 30的位置是代表字体颜色
echo -e "\033[31m 红色字 \033[0m"
echo -e "\033[34m 黄色字 \033[0m"
echo -e "\033[41;33m 红底黄字 \033[0m"
echo -e "\033[41;37m 红底白字 \033[0m"
# 需要使用参数-e,man  echo 可以知道-e:enable interpretation of backslash escapes。 ## 显示普通字符串 
echo "Hello World" ## 显示转义字符 
echo "\"Hello World\"" ## 显示变量 
name="zhangsan" 
echo "$name Hello World" ## 显示换行 
echo -e "OK! \n"  
echo "Hello World" ## 显示不换行 
echo -e "OK! \c" 
echo "Hello World" ## 显示结果定向至文件 
echo "Hello World" > myfile 
## > 代表覆盖
# >> 追加写入## 原样输出字符串 
echo '$name\"' ## 显示命令执行结果 
echo `date`

预定变量

参数处理 参数说明
$# 传递到脚本的参数个数
$*/$@ 以一个单字符串显示所有向脚本传递的参数。
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
$0 执行的文件名
$*  所有的参数
$@  所有的参数
对于后面说的for循环而言,上面两个没有区别$#  参数的个数
$$  当前进程的PID  # 此外,可以使用只读变量来获取父进程的PID:$PPID、获取执行脚本的用户ID:$UID
$?  上一个命令的返回值 0表示成功 示例1:
[root@master soft]# chmod +x b.sh 
[root@master soft]# ./b.sh a1 a2 a3 a4 a5
a1 a2 a3 a4 a5
a1 a2 a3 a4 a5
5
18988
1
[root@master soft]# cat b.sh 
#!/bin/bash
echo $*
echo $@
echo $#
echo $$

2.3 常量

使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。[root@master soft]# x=999
[root@master soft]# readonly x
[root@master soft]# x=111
-bash: x: 只读变量
如何删除readonly常量?

下载gdb

[root@master soft]# yum install gdb -y

删除

[root@master soft]# readonly x=123
[root@master soft]# cat << EOF | gdb
> attach $$
> call unbind_variable("x")
> detach
> EOF

2.4 数据类型

shell是一门解释型,弱类型,动态语言

概括地说,编程语言的划分方式有以下三种# 1、编译型or解释型# 2、强类型or弱类型
2.1 强类型语言: 数据类型不可以被忽略的语言
即变量的数据类型一旦被定义,那就不会再改变,除非进行强转。
在python中,例如:name = 'xiaohu',这个变量name在被赋值的那一刻,数据类型就被确定死了,是字符型,值为'xiaohu'。2.2 弱类型语言:数据类型可以被忽略的语言
比如linux中的shell中定义一个变量,是随着调用方式的不同,数据类型可随意切换的那种,即shell对数据类型的概念没有那么强的要求# 3、动态型or静态型
3.1 动态语言 :运行时才进行数据类型检查
即在变量赋值时,就确定了变量的数据类型,不用事先给变量指定数据类型3.2 静态语言:需要事先给变量进行数据类型定义所以综上所述,shell是一门解释型的弱类型动态语言

基本数据类型

数字类型
# int整型
定义:age=18
用于标识:年龄,等级,身份证号,qq号,个数# float浮点型
定义:salary=30000.0
用于标识:工资,身高,体重
字符串类型
#在shell中,加了引号的字符就是字符串类型定义:name='xiaohu' 
用于标识:描述性的内容,如姓名,性别,国籍,种族# 注意1:字符串包含空格必须加引号
[root@master soft]# msg="hello xiaohu"
[root@master soft]# msg=hello xiaohu
bash: xiaohu: 未找到命令...# 注意2:连续的字符不加引号包含也是可以的,但我们还是强烈建议加上引号,规范一些
[root@master soft]# msg=hello
[root@master soft]# echo $msg
hello
[root@master soft]# # 注意3:单引号与双引号是不同的
" "   弱引用,引号的特殊字符有意义
' '   强引用,引号内所有特殊字符都取消意义
[root@master soft]# name=“xiaohu”
[root@master soft]# echo "${name} is good"
xiaohu is good
[root@master soft]# echo '${name} is good'
${name} is good 
弱类型语言
[root@master soft]# x=10
[root@master soft]# y="3"
[root@master soft]# expr $x + $y
13
数组类型
# 1、什么是数组?
数组就是一系列元素的集合,一个数组内可以存放多个元素# 2、为何要用数组?
我们可以用数组将多个元素汇总到一起,避免单独定义的麻烦

数组分为两种
• 普通数组:只能使用整数作为数组索引
• 关联数组【字典】:可以使用字符串作为数组索引,需要用declare -A声明

普通数组
=================声明普通数组=================
# 方式一:array=(元素1 元素2 元素3)
array=(xiaohu 18 male)# 方式二:array=([key1]=value1 [key2]=value2 [key3]=value3)
array=([1]=111 [0]="two" [2]=333)# 方式三:依次赋值
array_new[0]=111
array_new[1]=222
array_new[2]="third"# 方式四:利用执行命令的结果设置数组元素:array=($(命令))  或者  array=(`命令`)
该方式会将命令的结果以空格为分隔符切成多个元素然后赋值给数组
[root@master soft]# ls /test
a.txt   b.txt
[root@master soft]# array3=(`ls /test`)
[root@master soft]# declare -a |grep array3
declare -a array3='([0]="a.txt" [1]="b.txt")'# ps:查看声明过的数组
declare -a=================访问普通数组=================
[root@master soft]# ip_array=(1.1.1.1 2.2.2.2 3.3.3.3)# 正向索引
[root@master soft]# echo ${ip_array[0]}
1.1.1.1
[root@master soft]# echo ${ip_array[1]}
2.2.2.2
[root@master soft]# echo ${ip_array[2]}
3.3.3.3
[root@master soft]# # 负向索引
[root@master soft]# echo ${ip_array[-1]}
3.3.3.3
[root@master soft]# echo ${ip_array[-2]}
2.2.2.2
[root@master soft]# echo ${ip_array[-3]}
1.1.1.1
关联数组
=================声明关联数组=================
[root@master soft]# declare -A info
[root@master soft]# info["name"]="xiaohu"
[root@master soft]# info["age"]=18
[root@master soft]# info["gender"]="male"
[root@master soft]# 
[root@master soft]# declare -A |grep info
declare -A info='([gender]="male" [name]="xiaohu" [age]="18" )'
[root@master soft]# 
[root@master soft]# echo ${info[*]}
male xiaohu 18
[root@master soft]# 
[root@master soft]# echo ${info["name"]}=================访问关联数组=================
declare -A info # 必须要先声明一下关联数组,才能进行赋值
[root@master soft]# info=(["name"]="xiaohu" ["age"]=18 ["gender"]="male")
[root@master soft]# echo ${info[0]}
xiaohu
[root@master soft]# echo ${info["age"]}
18
[root@master soft]# echo ${info["gender"]}
male
[root@master soft]# 

2.5 变量值相关常见操作

获取变量值的长度

[root@master soft]# echo ${#url}
15# 已知变量msg='hello world!',请统计出变量中包含的字符数量
[root@master soft]# echo ${#msg}
12

切片

# ${paramter:offset:length}[root@master soft]# msg="abcdef"
[root@master soft]# echo ${msg:3}  # 从3号索引开始,一直到最后
def
[root@master soft]# echo ${msg:3:2}  # 从3号索引开始,往后数2个字符
de
[root@master soft]# echo ${msg::3}  # 从0开始,往后数3个字符
abc

截断【截掉】

# =================》一、砍掉左边的字符《=================
# 1.1 简单使用 
[root@master soft]# url="www.shujia.com.cn"
[root@master soft]# echo ${url#www.}
shujia.com.cn# 1.2 结合 #* 非贪婪,默认情况下*是非贪婪,尽可能地少“吃”字符
[root@master soft]# echo ${url#*w}
ww.shujia.com.cn# 1.3 结合 ##* 贪婪,尽可能地多“吃”字符
[root@master soft]# echo ${url##*w}  # *会尽可能多地吃掉字符,一直匹配到最远的那个w才停下来
.shujia.com.cn# =================》二、砍掉右边的字符《=================
# 1.1 简单使用
[root@master soft]# url="www.shujia.com.cn"
[root@master soft]# echo ${url%.cn}
www.shujia.com# 1.2 结合%.*非贪婪
[root@master soft]# echo ${url%.*}
www.shujia.com
# 1.3 结合%%.*贪婪
[root@master soft]# echo ${url%%.*}
www

let操作

# (1) 变量的值
[root@master soft]# j=1
[root@master soft]# let ++j
[root@master soft]# echo $j
2
[root@master soft]# ++ 表示的是自加1,
i++ 表示先赋值运算,再自加1
++i 表示先自加1,再做赋值运算-- 表示的自减1
i-- 表示先赋值运算,再自减1
--i 表示先自减1,再做赋值运算# (2) 表达式的值
[root@master soft]# unset i
[root@master soft]# unset j
[root@master soft]# 
[root@master soft]# i=1
[root@master soft]# j=1
[root@master soft]# 
[root@master soft]# let x=i++  # 先把i赋值给x,然后再++
[root@master soft]# let y=++j  # 先++j,然后再把j的结果赋值给y
[root@master soft]# echo $i
2
[root@master soft]# echo $j
2
[root@master soft]# echo $x
1
[root@master soft]# echo $y
2

三、运算符

3.1 算术运算符

运算符 说明 举例
+ 加法 'expr $a + $b' 为 30。
- 减法 'expr $a-$b'结果为-10。
* 乘法 'expr $a * $b' 结果为 200。
/ 除法 'expr$b/$a'结果为2。
% 取余 'expr $b % $a' 结果为0。
= 赋值 a=$b将把变量b的值赋给a
== 相等,用于比较两个数字,相同返回true [$a == $b]返回false。
!= 不相等,用于比较两个数字,不相同返回true [$a != $b]返回true。

算术运算符需要配合以下操作符使用

# 浮点运算
bc  # 整数运算
expr
$(())
$[]
let
bc 计算工具( yum install bc -y )
[root@master soft]# res=`echo "1+1" | bc`
[root@master soft]# echo $res
2[root@master soft]# res=`echo "10%3" | bc`
[root@master soft]# echo $res
1[root@master soft]# res=`echo "1.2+1.3" | bc`
[root@master soft]# echo $res
2.5[root@master soft]# res=`echo "5.0+3.0" | bc`
[root@master soft]# echo $res
8.0
expr
[root@master soft]# res=`expr 5 / 3`  # 不支持浮点计算
[root@master soft]# echo $res
1[root@master soft]# res=`expr 1+1`  # 注意:要有空格
[root@master soft]# echo $res
1+1
[root@master soft]# res=`expr 1 + 1`
[root@master soft]# echo $res
2如果是乘法,如需要转义\*
[root@master soft]# echo `expr 3 \* 10`
30
[root@master soft]# 
$[]
[root@master soft]# echo $[$num1+$num2]  # 等同于 echo $[num1+num2]
333
[root@master soft]# echo $[1.3+3.1] 
-bash: 1.3+3.1: 语法错误: 无效的算术运算符 (错误符号是 ".3+3.1")
let赋值 只支持赋值操作
[root@master soft]# let res=1+1
[root@master soft]# echo $res
2
[root@master soft]# 
[root@master soft]# let res=50/5
[root@master soft]# echo $res
10
[root@master soft]# let c=1.3*3
-bash: let: c=1.3*3: 语法错误: 无效的算术运算符 (错误符号是 ".3*3"

3.2 文件测试运算符

#!/bin/bash file="/var/node/test.sh" 
if [ -r $file ] 
thenecho "文件可读" 
elseecho "文件不可读" 
fiif [ -w $file ] 
thenecho "文件可写" 
elseecho "文件不可写" 
fiif [ -x $file ] 
thenecho "文件可执行" 
elseecho "文件不可执行" 
fiif [ -f $file ] 
thenecho "文件为普通文件" 
elseecho "文件为特殊文件" 
fiif [ -d $file ] 
thenecho "文件是个目录" 
elseecho "文件不是个目录" 
fiif [ -s $file ] 
thenecho "文件不为空" 
else
echo "文件为空" 
fi

3.3 字符串测试运算符

# == 判断两个字符串是否相等
[root@master soft]# [ "aaa" == "aaa" ];echo $?
0# != 判断两个字符串是否不相等
[root@master soft]# [ "aaa" != "aaa" ];echo $?
1# -z 判断字符串长度是否为0
[root@master soft]# ip=""
[root@master soft]# [ -z "$ip" ];echo $?  # 注意引号
0
[root@master soft]# ip='1.1.1.1'
[root@master soft]# [ -z "$ip" ];echo $?
1# -n 判断字符串长度是否不为0
[root@master soft]# [ -n "$ip" ];echo $?  # 注意加引号
1

3.4 数值测试符(比较运算符)

运算符 说明 举例
-eq 检测两个数是否相等,相等返回true [$a -eq $b ]返回 false。
-ne 检测两个数是否不相等,不相等返回true [$a -ne $b ]返回 true。
-gt 检测左边的数是否大于右边的,如果是,返回true [$a -gt $b ]返回 false.
-lt 检测左边的数是否小于右边的,如果是,返回true [$a -It $b ]返回 true。
-ge 检测左边的数是否大于等于右边的,如果是,返回true [$a -ge $b ]返回 false。
-le 检测左边的数是否小于等于右边的,如果是,返回true [$a -le $b ]返回 true.
[root@master soft]# [ 10 -eq 10 ];echo $?
0
[root@master soft]#  [ 10 -eq 10 -a 10 \> 3 ];echo $?
0

3.5 关系运算符

需要结合(())进行使用

[root@master soft]# x=100[root@master soft]# (($x>10))
[root@master soft]# echo $?
0[root@master soft]# (($x < 10));echo $?
1[root@master soft]# (($x == 100));echo $?
0[root@master soft]# (($x != 100));echo $?
1[root@master soft]# (($x != 100)) && (("xiaohu" == "xiaohu"))
[root@master soft]# echo $?
1[root@master soft]# (($x != 100)) || (("xiaohu" == "xiaohu"))
[root@master soft]# echo $?
0[root@master soft]# (($x != 100 && "xiaohu" == "xiaohu"));echo $?
1[root@master soft]# (($x != 100 || "xiaohu" == "xiaohu"));echo $?
0

3.6 赋值运算符

[root@master soft]# x=10
[root@master soft]# ((x%3))
[root@master soft]# echo $x
10
[root@master soft]# ((x%=3))
[root@master soft]# echo $x
1

# 相关括号:
格式1: test 条件表达式
格式2: [ 条件表达式 ] -eq -lt -gt -le -ge -ne
格式3: (()) 数值比较,运算   += -= %= == != < > <= >=  && ||格式4: [[ 条件表达式 ]],支持正则  =~# 双中括号的正则
[root@master soft]# [[ "$USER" ==  "root" ]];echo $?  # 注意内层[]中包含的内容必须左右两侧加空格
0
[root@master soft]# [[ "$USER" ==  "root" ]];echo $?  # 一个等号也行两个等号也可以额
0# 此外[[]]内部是可以使用正则的,注意:正则表达式不要加引号
[root@master soft]# [[ "$USER" =~ ^wyh$ ]];echo $?  # 正则表达式不要加引号
1
[root@master soft]# [[ "$USER" =~ ^root$ ]];echo $?  # 正则表达式不要加引号
0
[root@master soft]# [[ ! "$USER" =~ t$ ]] && echo 此时不是管理员登录 || echo 是管理员登录
是管理员登录[root@master soft]# num1=123
[root@master soft]# [[ "$num1" =~ ^[0-9]+$ ]];echo $?  # 判断是否是数字
0
[root@master soft]# [[ "$num1" =~ ^[0-9]+$ ]] && echo "是数字"
是数字[root@master soft]# num2=abc123de
[root@master soft]# [[ "$num2" =~ ^[0-9]+$ ]];echo $?
1
[root@master soft]# [[ "$num2" =~ ^[0-9]+$ ]] || echo "num2不是数字"
num2不是数字

3.7 布尔运算符

运算符 说明 举例
非运算,表达式为true则返回false,否则退回true。 [ ! false ]返回 true。
-o 或运算,有一个表达式为true则返回true。 [ $a -It 20 -o $b -gt 100 ]返回 true。
-a 与运算,两个表达式都为true才返回true. [ $a -It 20 -a $b -gt 100 J 返回 false。

[ $a -It 20 -a $b -gt 100 ];echo $?

3.8 逻辑运算符

运算符 说明 举例
&& 逻辑的AND [[$a -It 100 && $b-gt 100 ]]返回 false
|| 逻辑的OR [[$a -It 100 || $b -gt 100 ]]返回 true

四、流程控制

4.1 if语句

if 条件
then要执行的命令1要执行的命令2要执行的命令3...
fiif 条件;then要执行的命令1要执行的命令2要执行的命令3...
fi# 上述语法可以用一行代码代替
[ 条件信息 ] && xxx

双分支

if 条件;then要执行的命令1要执行的命令2要执行的命令3...
else要执行的命令1要执行的命令2要执行的命令3...
fi# 上述语法可以用一行代码代替
[ 条件信息 ] && xxx || xxxx

举例:

#!/bin/bash
username='xiaohu'
password='123'
read -p 'user: ' name 
read -p 'passwd: ' passwdif [ $name == $username -a $passwd == $password ]
thenecho 'login successful'
elseecho 'username or password err'
fi

多分支

if 条件;then要执行的命令1要执行的命令2要执行的命令3...
elif 条件;then要执行的命令1要执行的命令2要执行的命令3...
elif 条件;then要执行的命令1要执行的命令2要执行的命令3...
...
else要执行的命令1要执行的命令2要执行的命令3...
fi

举例:

======================版本1======================
#!/bin/bash
age=87
read -p 'num: ' nif [ $n -eq $age ];thenecho 'you get it'
elif [ $n -gt $age ];thenecho 'too big'
elif [ $n -lt $age ];thenecho 'too small'
fi======================版本2======================
#!/bin/bashread -p ">>> " num[[ ! $num =~ ^[0-9]+$ ]] && echo "请输入数字" && exitif [ $num -gt 18 ];thenecho "too big"
elif [ $num -lt 18 ];thenecho "too small"
elseecho "you got it"
fi

4.2 case选择

case 变量 in
模式1)命令序列1;;
模式2)命令序列2;;
模式3)命令序列3;;
*)无匹配后命令序列
esac

注意:

case语句只支持shell通配符,例如:*表示任意字符串,?表示任意字符,中括号表示字符集如[a-z]表示一个小写字母
如果要处理正则表达式则需要使用用if [[ 字符串 =~ "正则" ]]这种形式

案例:

#!/bin/bash
read -p "username: " -t 5 username
echo
if [ -z $username ];thenusername="default"
ficase $username in
root)echo "管理员用户";;
xiaohu)echo "普通用户";;
default)echo "默认用户";;
*)echo "其他用户"
esac

4.3 while循环

# 一、while语句结构:条件为真时,执行循环体代码
while 条件
do循环体
done# 二、until语法结构:条件为假时,一直执行循环体代码,直到条件变为真
until 条件
do循环体
done

案例:

[root@master soft]# cat a.sh 
#!/bin/bashx=0
while (($x<3))
doecho $x  # 0,1,2let x++
doneecho "================"y=0
until (($y==3))
doecho $y # 0,1,2let y++
done[root@master soft]# ./a.sh 
0
1
2
================
0
1
2
[root@master soft]# 

流程控制语句:

continue:默认退出本次循环

break:默认退出本层循环

4.4 for循环

# Shell风格语法
for 变量名 [ in 取值列表 ]
do循环体
done# C语言风格语法
for ((初值;条件;步长))
do  循环体
done

案例1 shell风格

for i in {1..10}
doecho $i
done

案例2:C语言风格

for ((i=1;${i}<=10;i++))
doecho $i
done

4.5 扩展使用select

select var in ...
do...break
done

案例:

[root@master soft]#  cat select2.sh 
#!/bin/bash
PS3='choose one: ' # select默认使用PS3变量的值做提示符
echoselect var in $1 $2 $3 $4
doechoecho "your choose is $var"echo "OK"echobreak # 跳出select,否则是死循环
done[root@master soft]# 
[root@master soft]# ./select2.sh 苹果 梨 蔬菜 香蕉 1) 苹果
2) 梨
3) 蔬菜
4) 香蕉
5) 茄子
choose one: 1your choose is 苹果
OK

五、函数

函数的定义

#语法:
[ function ] funname [()]
{命令1;命令2;命令3;...[return int;]
}# 示例1:完整写法
function 函数名() {函数要实现的功能代码
}# 示例2:省略关键字(),注意此时不能省略关键字function
function 函数名 {函数要实现的功能代码
}# 示例3:省略关键字function
函数名() {函数要实现的功能代码
}

函数的调用

# 语法:
函数名  # 无参调用
函数名 参数1 参数2  # 有参调用# 示例
function test1(){echo "执行第一个函数"
}function test2 {echo "执行第二个函数"
}test3(){echo "执行第三个函数"
}# 调用函数:直接引用函数名字即调用函数,会触发函数内代码的运行
test1
test2
test3

函数调用时传递参数

# 调用函数test1,在其后以空格为分隔符依次罗列参数 
test1 111 222 333 444 555

函数内部使用$n来取值

[root@master soft]# cat b.sh 
function test1(){echo "...start..."echo $1echo $2echo $3echo "...end..."
}test1 111 222 333 444 555  # 为函数体传参[root@master soft]# ./b.sh 
...start...
111
222
333
...end...
注意1:不要和脚本外部传参搞混淆
[root@master soft]# cat b.sh 
function test1(){echo "...start..."echo "这是函数内:$1"echo "这是函数内:$2"echo "这是函数内:$3"echo "...end..."
}# test1 111 222 333 444 555
test1echo "这是脚本级的参数$1"
echo "这是脚本级的参数$2"
echo "这是脚本级的参数$3"[root@master soft]# 
[root@master soft]# 
[root@master soft]# ./b.sh xxx yyy zzz mmm nnn
...start...
这是函数内:
这是函数内:
这是函数内:
...end...
这是脚本级的参数xxx
这是脚本级的参数yyy
这是脚本级的参数zzz
[root@master soft]# 
注意2:$*和$@
# 1、当$*和$@没有被引号引用起来的时候,它们确实没有什么区别,都会把位置参数当成一个个体。# 2、"$*" 会把所有位置参数当成一个整体(或者说当成一个单词),如果没有位置参数,则"$*"为空,如果有两个位置参数并且分隔符为空格时,"$*"相当于"$1 $2"# 3、"$@"  会把所有位置参数当成一个单独的字段,如果没有位置参数,则"$@"展开为空(不是空字符串,而是空列表),如果存在一个位置参数,则"$@"相当于"$1",如果有两个参数,则"$@"相当于"$1"  "$2"等等
[root@master soft]# cat b.sh 
echo "=======函数test1==========="
function test1(){echo "$*"  # 111 222 333 444 555echo "$@"  # 111 222 333 444 555echo $#    # 5echo $$    # 87380echo $?    # 0
}test1 111 222 333 444 555echo "=======函数test2==========="
function test2(){for i in "$*"  # 注意:$*不加引号结果与$@一模一样doecho $idone
}test2 111 222 333 "444 555"  # 注意"444 555"被引号引成了一个参数
# 运行结果为:111 222 333 444 555echo "=======函数test3==========="
function test3(){for i in "$@"  # 注意:$*不加引号结果与$@一模一样doecho $idone
}test3 111 222 333 "444 555"  # 注意"444 555"被引号引成了一个参数
# 运行结果为:
# 111
# 222
# 333
# 444 555

函数返回值的问题

1. 当函数体中没有return,那么最后一条命令(运行成功为0,其他不为0)作为返回值

[root@master soft]# cat b.sh 
function test1(){echo 111echo 222echo 333xxx  # 运行该命令出错
}test1
echo $?
[root@master soft]# ./b.sh 
111
222
333
./b.sh:行5: xxx: 未找到命令
127

2. 有return的时候,注意,return后面只能跟整数并且【0-255】,在shell中0表示true, 1表示false

[root@master soft]# cat b.sh 
function test1(){echo 111echo 222echo 333return 0
}test1
echo $?  # 用$?获取函数的返回值
[root@master soft]# ./b.sh 
111
222
333
0

局部变量

使用local关键字定义在函数内部的变量叫做局部变量,只能在函数内部使用

[root@master soft]# cat hello.sh 
#!/bin/bash# 定义函数
function test(){local x=111echo "函数内访问x:$x"
}# 调用函数
testecho "在函数外即全局访问x:$x"  # 无法访问函数内的局部变量

全局变量

可以在当前shell进程中使用, 所谓全局变量,就是降量在当前的整个Shell进程中都有效。每个Shell进程都有自己的作用域,彼此之间互不影响。在Shell中定义的变量,默认就都是全局变量。

[root@master soft]# cat hello.sh 
#!/bin/bash
x=2222function test(){echo "函数内访问x:$x"
}
test
echo "在函数外即全局访问x:$x" 

注意1:在函数内定义的变量,如果没有用local声明,那么默认也是全局变量

[root@master soft]# cat hello.sh 
#!/bin/bash
function test(){x=2222  # 全局变量
}
test
echo "在函数外即全局访问x:$x"  [root@master soft]# ./hello.sh 
在函数外即全局访问x:2222

注意2:每执行一个解释器,都会开启一个解释的shell进程,每个shell进程都有自己的作用域彼此互不干扰

[root@master soft]# x=111  # 该变量仅仅只在当前shell进程中有效,对新的shell进程无影响
[root@master soft]# echo $x
111
[root@master soft]# bash  # 执行bash解释器,则开启一个新的进程,或者干脆直接打开一个新的终端
[root@master soft]# echo $x[root@master soft]# 

注意3:

全局变量的作用范围是当前的Shell进程,而不是当前的Shell脚本文件,它们是不同的概念。打开一个Shell窗口就创建了一个Shell进程,打开多个Shell窗口就创建了多个Shell进程,每个Shell进程都是独立的,拥有不同的进程ID。在—Shell进程中可以使用source命令执行多个Shell脚本文件,此时全局变量在这些脚本文件中都有效。

[root@master soft]# echo $x[root@master soft]# cat hello.sh 
#!/bin/bash
function test(){x=2222  # 全局变量
}
test[root@master soft]# source hello.sh  # 在当前shell进程中执行,产生一个全局变量x
[root@master soft]# echo $x  # 在当前shell进程中访问全局变量x,可以看到
2222
[root@master soft]# 
[root@master soft]# 
[root@master soft]# cat aaa.sh 
#!/bin/bash
echo $x[root@master soft]# source aaa.sh # 在当前shell进程中访问全局变量x,同样可以看到
2222

注意4:全局变量只在当前Shell进程中有效,对其它Shell进程和子进程都可以使用

如果使用export命令将全局变量导出,那么它就在所有的子进程中也有效了,这称为“环境变量”。
环境变量被创建时所处的Shell进程称为父进程,如果在父进程中再创建一个新的进程来执行Shell命令,那么这
个新的进程被称作Shell子进程。当Shell子进程产生时,它会继承父进程的环境变量为自己所用,所以说环境变
量可从父进程传给子进程。不难理解,环境变量还可以传递给孙进程。

[root@master soft]# export y=333  # 爷爷
[root@master soft]# bash  # 爸爸
[root@master soft]# echo $y
333
[root@master soft]# bash  # 孙子
[root@master soft]# echo $y
333ps:通过exit命令可以一层一层地退出 Shell。# 命令
set:显示所有变量
env:环境变量

注意5:环境变量只能向下传递不能向上传递

注意6:两个没有父子关系的shell进程不能传递环境变量

我们一直强调的是环境变量在 Shell 子进程中有效,并没有说它在所有的 Shell 进程中都有效;如果你通过终端创建了一个新的 Shell 窗口,那它就不是当前 Shell 的子进程,环境变量对这个新的 Shell 进程仍然是无效的。

注意7:环境变量也是临时的

[root@master soft]# ps -ef
root     123436  0.0  0.1 116356  2960 pts/0    Ss   21:52   0:00 -bash
root     123492  0.0  0.1 116472  2932 pts/0    S    21:54   0:00 bash
root     123520  0.0  0.1 116440  2988 pts/0    S    21:54   0:00 bash注意:
# -开头的bash代表是在登录终端登录的顶级shell进程
# 非-开头的bash代表的是子shell进程
# 一旦退出了在终端登录的顶级shell,那么该终端下开启的所有子shell都会被回收,export设置的环境变量随即消失

练习题(晚上离开教室之前交)

# 1、脚本案例: 编写小脚本, 可以实现2位数加减乘除运算# 2、脚本案例: 编写判断输入参数是否是整数信息脚本# 3、如何利用脚本计算1+2+3+4..10总和数值# 4、根据考试成绩输出对应的礼物,90分以上爸爸给买电脑,80分以上爸爸给买手机, 60分以上爸爸请吃一顿大餐,60分以下爸爸给买学习资料。要求:该题使用多重if完成# 5、输入一批整数,使用循环求出最大值与最小值,输入0时结束。# 6、给20块钱买可乐,每瓶可乐3块钱,喝完之后退瓶子可以换回1块钱,问最多可以喝到多少瓶可乐。# 7、求九九乘法表

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/869215.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

logstash输出到loki

运行logstash # logstash version: 3 services:logstash:image: docker.elastic.co/logstash/logstash:8.12.0container_name: logstash_serverrestart: alwaysports:- 8065:8065environment:- LS_JAVA_OPTS=-Xmx1024m -Xms1024mvolumes:- ./config/logstash.conf:/etc/logstas…

【Electron 应用安全测试基础】Electron 框架介绍

免责声明 ⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。所有渗透都需获取授权!一、引言 跨平台桌面应用开发的演进带来了一系列独特的挑战,主要体现在如何确保在 Windows、macOS 和基于 Linux…

07jdk7u21原生利用链

JDK7u21 反序列化的关键在于找到可以动态方法执行的代码:例如CC链中的Transformer,CB链中的PropertyUtils#getPropertyJDK7u21中动态方法执行的点,AnnotationInvocationHandler#equalsImpl中的hisValue = memberMethod.invoke(o)。 private Boolean equalsImpl(Object o) {i…

英语语法(介词和连词)

认识介词 例子: 例子: 识别介词 时间介词 at 精确的时间 by 不缺定的时间 for 持续的时间 in 固定的时间 on 某一天的时间 since 开始时间 until 直到 空间介词 at 指一个点 by 近的意思 from 从别处到这里 in 一个封闭的区域 off 离开 on 开启 out 方向 远离…

一文读懂如何创建食品加工和包装 SOP

在食品行业中,确保产品的安全性和质量是至关重要的。为了实现这一目标,建立一套详尽且高效的标准操作程序(SOP)对于食品加工与包装环节来说不可或缺。本文将引导您深入理解如何高效创建食品加工与包装SOP,并巧妙融入helplook工具,以提升流程管理的精确性和效率。一、明确…

高性能、零内存分配的Go日志库--Zerolog

简介 Zerolog 是一个高性能、零内存分配的 Go 日志库。 它为不需要垃圾回收的延迟敏感型应用程序提供结构化日志记录功能。 您可以以完全零分配的方式使用,这样在初始化记录器对象后,堆上不会再分配其他对象,从而防止触发垃圾回收。 Zerolog 包提供了一个专用于 JSON 输出的…

Jar Analyzer:JAR包分析工具

工具介绍 一个JAR包分析工具,批量分析,SCA漏洞分析,方法调用关系搜索,字符串搜索,Spring组件分析,信息泄露检查,CFG程序分析,JVM栈帧分析,进阶表达式搜索,字节码指令级的动态调试分析,反编译JAR包一键导出,一键提取序列化数据恶意代码,一键分析BCEL字节码。 Jar A…

第二十次作业

1、对bluecms进行代码审计,分析复现文件上传、ssti模板注入、文件删除等漏洞 文件上传:ssti模板注入: bluecms采⽤了smarty模板引擎可以在模板中插⼊恶意的代码,从⽽执⾏任意命令。此处可知smarty使⽤的界定符为{#和#},参考smarty官⽅⽂档可知,可以使⽤{#php#}code{#/php…

【JAVA开发】企业Java开发:七款提升开发者工作效率的Java分析工具

一、引言 编写正确的代码至关重要,但同样重要的是理解代码在实际环境中的表现。Java 分析工具在这方面提供了极大的便利,它们可以帮助您深入了解程序的内部运作。虽然进行性能分析可能需要额外的时间投入,但它最终能够为您节省大量调试时间。 Java 分析器提供了关于 CPU 使用…

JS-32 数组方法_shift()/unshift()

shift方法用于删除数组的第一个元素,并返回该元素。注意,该方法会改变原数组 var arr=[字符串,zifuchuan,前端]; arr.shift()//字符串 arr//[zifuchuan,前端] shift方法可以遍历并清空一个数组 var list=[1,2,3,4,5,6]; var item;while(item=list.shift()){ console.log(ite…

【勒索病☠】盘点全球主流Linux平台的勒索病毒

前言 美国网络信息安全公司CrowdStrike在2021年的攻击数据报告中,总结与2020年度相比,2021年度针对Linux系统的恶意软件增加了35%,其实最近几年针对Linux平台下的恶意软件数据一直在不断的增加,这些恶意软件主要包含僵尸网络、挖矿病毒、勒索病毒、远控木马等,随着云计算平…

再谈Redux

2025年再聊前端状态管理似乎是一件不必要的事,毕竟相关文章已堆积得如山如海。但在这些文章或视频内容中,我并没有找到自己喜欢的方案,准确的说是使用方式。所以这篇文章不做技术分析,主要聊聊个人对状态管理的理解,并分享独特的redux使用的方式。 状态管理 先分享一个有趣…