Shell基础语法——流程控制、函数
admin
2024-03-05 19:39:23
0

Shell 流程控制

选择结构:分别是 if else 语句和 case in 语句。

if 语句:

语法1:(if 语句)

if  condition
thenstatement(s)
fi

condition是判断条件,如果 condition 成立(返回“真”),那么 then 后边的语句将会被执行;如果 condition 不成立(返回“假”),那么不会执行任何语句。

语法2:(if 语句)

if  condition;  thenstatement(s)
fi

请注意 condition 后边的分号;,当 if 和 then 位于同一行的时候,这个分号是必须的,否则会有语法错误。

语法3:(if else 语句)

if  condition
thenstatement1
elsestatement2
fi

如果 condition 成立,那么 then 后边的 statement1 语句将会被执行;否则,执行 else 后边的 statement2 语句。

语法4:(if elif else 语句)

if  condition1
thenstatement1
elif condition2
thenstatement2
elif condition3
thenstatement3
……
elsestatementn
fi

注意,if 和 elif 后边都得跟着 then。

case in 语句:

case expression inpattern1)statement1;;pattern2)statement2;;pattern3)statement3;;……*)statementn
esac

case、in 和 esac 都是 Shell 关键字,expression 表示表达式,pattern 表示匹配模式。

  • expression 既可以是一个变量、一个数字、一个字符串,还可以是一个数学计算表达式,或者是命令的执行结果,只要能够得到 expression 的值就可以。
  • pattern 可以是一个数字、一个字符串,甚至是一个简单的正则表达式。

case 会将 expression  的值与 pattern1、pattern2、pattern3 逐个进行匹配:

  • 如果 expression 和某个模式(比如 pattern2)匹配成功,就会执行这模式(比如 pattern2)后面对应的所有语句(该语句可以有一条,也可以有多条),直到遇见双分号;;才停止;然后整个 case 语句就执行完了,程序会跳出整个 case 语句,执行 esac 后面的其它语句。
  • 如果 expression 没有匹配到任何一个模式,那么就执行*)后面的语句(*表示其它所有值),直到遇见双分号;;或者esac才结束。*)相当于多个 if 分支语句中最后的 else 部分。

case in 和正则表达式

case in 的 pattern 部分支持简单的正则表达式,具体来说,可以使用以下几种格式:

格式说明
*表示任意字符串。
[abc]表示 a、b、c 三个字符中的任意一个。比如,[15ZH] 表示 1、5、Z、H 四个字符中的任意一个。
[m-n]表示从 m 到 n 的任意一个字符。比如,[0-9] 表示任意一个数字,[0-9a-zA-Z] 表示字母或数字。
|表示多重选择,类似逻辑运算中的或运算。比如,abc | xyz 表示匹配字符串 "abc" 或者 "xyz"。

对*)的几点说明:

Shell case in 语句中的*)用来“托底”,万一 expression 没有匹配到任何一个模式,*)部分可以做一些“善后”工作,或者给用户一些提示。

可以没有*)部分。如果 expression 没有匹配到任何一个模式,那么就不执行任何操作。

除最后一个分支外(这个分支可以是普通分支,也可以是*)分支),其它的每个分支都必须以;;结尾,;;代表一个分支的结束,不写的话会有语法错误。最后一个分支可以写;;,也可以不写,因为无论如何,执行到 esac 都会结束整个 case in 语句。

最后一个分支*)并不是什么语法规定,它只是一个正则表达式,*表示任意字符串,所以不管 expression 的值是什么,*)总能匹配成功。

循环结构:

while 循环:

while condition
dostatements
done

 while 循环的执行流程为:

  • 先对 condition 进行判断,如果该条件成立,就进入循环,执行 while 循环体中的语句,也就是 do 和 done 之间的语句。这样就完成了一次循环。
  • 每一次执行到 done 的时候都会重新判断 condition 是否成立,如果成立,就进入下一次循环,继续执行 do 和 done 之间的语句,如果不成立,就结束整个 while 循环,执行 done 后面的其它 Shell 代码。
  • 如果一开始 condition 就不成立,那么程序就不会进入循环体,do 和 done 之间的语句就没有执行的机会。

until循环

unti 循环和 while 循环恰好相反,当判断条件不成立时才进行循环,一旦判断条件成立,就终止循环。 

until condition
dostatements
done

 一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。

for 循环

语法1:

for var in value_list
docommand1command2...commandN
done

当变量值在列表里,for 循环即执行一次所有命令,使用变量名获取列表中的当前取值。in 列表可以包含替换、字符串和文件名。

in列表是可选的,如果不用它,for循环使用命令行的位置参数。

对 value_list 的说明

取值列表 value_list 的形式有多种,你可以直接给出具体的值,也可以给出一个范围,还可以使用命令产生的结果,甚至使用通配符

  • 直接给出具体的值:可以在 in 关键字后面直接给出具体的值,多个值之间以空格分隔 ;

  • 给出一个取值范围:{start..end}  注意中间用两个点号相连,这种形式只支持数字和字母;

  • 使用命令的执行结果:使用反引号``或者$()都可以取得命令的执行结果;

  • 使用 Shell 通配符:一种精简化的正则表达式,通常用来匹配目录或者文件,而不是文本;

  • 使用特殊变量:例如 $#、$*、$@、$?、$$ 等,可省略,省略后效果与$@一样。

语法2: 

for((exp1; exp2; exp3))
dostatements
done

 for 循环中的三个表达式

for 循环中的 exp1(初始化语句)、exp2(判断条件)和 exp3(自增或自减)都是可选项,都可以省略(但分号;必须保留)。

  1. 省略 exp1:将exp1移到了 for 循环的外面。
  2. 省略 exp2:可以在循环体内部使用 break 关键字强制结束循环
  3. 省略了 exp3:可在循环体中加入修改变量的语句。

 无限循环

while :
docommand
done
#------------------
while true
docommand
done
#------------------
for (( ; ; ))

 select in循环

select in 循环用来增强交互性,它可以显示出带编号的菜单,用户输入不同的编号就可以选择不同的菜单,并执行不同的功能。
select in 是 Shell 独有的一种循环,非常适合终端(Terminal)这样的交互场景

select variable in value_list
dostatements
done

 举例:

#!/bin/bash
echo "What is your favourite OS?"
select name in "Linux" "Windows" "Mac OS" "UNIX" "Android"
doecho $name
done
echo "You have selected $name"运行结果:
What is your favourite OS?
1) Linux
2) Windows
3) Mac OS
4) UNIX
5) Android
#? 4↙
You have selected UNIX
#? 1↙
You have selected Linux
#? 9↙
You have selected
#? 2↙
You have selected Windows
#?^D

#?用来提示用户输入菜单编号;^D表示按下 Ctrl+D 组合键,它的作用是结束 select in 循环。

运行到 select 语句后,取值列表 value_list 中的内容会以菜单的形式显示出来,用户输入菜单编号,就表示选中了某个值,这个值就会赋给变量 variable,然后再执行循环体中的 statements(do 和 done 之间的部分)。

每次循环时 select 都会要求用户输入菜单编号,并使用环境变量 PS3 的值作为提示符,PS3 的默认值为#?,修改 PS3 的值就可以修改提示符。

如果用户输入的菜单编号不在范围之内,例如上面我们输入的 9,那么就会给 variable 赋一个空值;如果用户输入一个空值(什么也不输入,直接回车),会重新显示一遍菜单。

注意,select 是无限循环(死循环),输入空值,或者输入的值无效,都不会结束循环,只有遇到 break 语句,或者按下 Ctrl+D 组合键才能结束循环。

跳出循环

在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell 使用两个命令来实现该功能:break 和 continue

在C语言、C++、C#、Python、Java 等大部分编程语言中,break 和 continue 只能跳出当前层次的循环,内层循环中的 break 和 continue 对外层循环不起作用;但是 Shell 中的 break 和 continue 却能够跳出多层循环,也就是说,内层循环中的 break 和 continue 能够跳出外层循环。

break 关键字 

语法:break n

n 表示跳出循环的层数,如果省略 n,则表示跳出当前的整个循环。break 关键字通常和 if 语句一起使用,即满足条件时便跳出循环。

例1:如果 break 后面不跟数字的话,表示跳出当前循环,对于有两层嵌套的循环,就得使用两个 break 关键字。

#!/bin/bash
i=0
while ((++i)); do  #外层循环if((i>4)); thenbreak  #跳出外层循环fij=0;while ((++j)); do  #内层循环if((j>4)); thenbreak  #跳出内层循环fiprintf "%-4d" $((i*j))doneprintf "\n"
done

例2:在 break 后面跟一个数字,让它一次性地跳出两层循环

#!/bin/bash
i=0
while ((++i)); do  #外层循环j=0;while ((++j)); do  #内层循环if((i>4)); thenbreak 2  #跳出内外两层循环fiif((j>4)); thenbreak  #跳出内层循环fiprintf "%-4d" $((i*j))doneprintf "\n"
done

修改后的代码将所有 break 都移到了内层循环里面。读者需要重点关注break 2这条语句,它使得程序可以一次性跳出两层循环,也就是先跳出内层循环,再跳出外层循环。

continue 关键字

语法:continue n

n 表示循环的层数:

  • 如果省略 n,则表示 continue 只对当前层次的循环语句有效,遇到 continue 会跳过本次循环,忽略本次循环的剩余代码,直接进入下一次循环。
  • 如果带上 n,比如 n 的值为 2,那么 continue 对内层和外层循环语句都有效,不但内层会跳过本次循环,外层也会跳过本次循环,其效果相当于内层循环和外层循环同时执行了不带 n 的 continue。这么说可能有点难以理解,稍后我们通过代码来演示。

【实例】使用 continue 跳出多层循环,请看下面的代码: 

#!/bin/bash
for((i=1; i<=5; i++)); dofor((j=1; j<=5; j++)); doif((i*j==12)); thencontinue 2fiprintf "%d*%d=%-4d" $i $j $((i*j))doneprintf "\n"
done

 从运行结果可以看出,遇到continue 2时,不但跳过了内层 for 循环,也跳过了外层 for 循环。

Shell函数 

 Shell 函数的本质是一段可以重复使用的脚本代码,这段代码被提前编写好了,放在了指定的位置,使用时直接调取即可。

Shell 函数定义的语法格式如下:

function name() {statements[return value]
}

对各个部分的说明:

  • function是 Shell 中的关键字,专门用来定义函数;
  • name是函数名;
  • statements是函数要执行的代码,也就是一组语句;
  • return value表示函数的返回值,其中 return 是 Shell 关键字,专门用在函数中返回一个值;这一部分可以写也可以不写。

{ }包围的部分称为函数体,调用一个函数,实际上就是执行函数体中的代码。

简化写法

# 省略function 关键字:
name() {statements[return value]
}# 省略函数名后面的小括号:
function name {statements[return value]
}

函数参数

Shell 中的函数在定义时不能指明参数,但是在调用时却可以传递参数。

在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数...  $10 不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。

特殊字符用来处理参数:

参数处理说明
$#传递到脚本或函数的参数个数
$*以一个单字符串显示所有向脚本传递的参数
$$脚本运行的当前进程ID号
$!后台运行的最后一个进程的ID号
$@与$*相同,但是使用时加引号,并在引号中返回每个参数。
$-显示Shell使用的当前选项,与set命令功能相同。
$?显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

函数调用

调用 Shell 函数时可以给它传递参数,也可以不传递。如果不传递参数,直接给出函数名字即可:

name

如果传递参数,那么多个参数之间以空格分隔:

name param1 param2 param3

不管是哪种形式,函数名字后面都不需要带括号。

Shell 函数在定义时不能指明参数,但是在调用时却可以传递参数,并且给它传递什么参数它就接收什么参数。

相关内容

热门资讯

ZDS助力金融交易平权|打破壁... 金融交易平权,是全球金融发展的终极愿景之一,即让不同地域、不同资金规模、不同交易经验的用户,都能平等...
美元反弹只是“死猫跳”?分析师... 来源:金十数据 美以对伊朗开战引发美元反弹,但华尔街对此存疑,并预计这波涨势恐难持久…… 据路透社...
地缘冲突带火化工品行情,恐慌过... 来源:第一财经 预计随着市场情绪逐步降温,化工板块也将逐步从全面普涨,过渡到基于基本面的验证阶段。 ...
存储芯片超级风口 佰维存储前两... 来源:观点地产网 观点网 3月4日,A股市场陷入调整,三大股指集体收跌。 截至收盘,上证指数报408...
镜头直击丨探访遭空袭后的德黑兰... ↑↓这是3月4日在伊朗首都德黑兰市中心革命广场附近拍摄的被损毁建筑。 新华社记者 沙达提 摄影报道
2月A股新开252万户,日均水... 扬子晚报网3月4日讯(记者 范晓林 薄云峰)据上交所最新披露2026年2月A股新开户数据,当月A股新...
全球陷入能源“焦虑”,新能源能... 一场突如其来的中东“风暴”,正在席卷全球能源市场。 3月4日,国际油价延续涨势,国际原油期货结算价大...
原创 黄... 简单说:这个世界不缺油,油太多,用不完,买不完。 作者:今纶 战争在继续,黄金、石油怎么走? 我们...
“年轻化”与“她力量”,汾酒奏... 在推进“年轻化”战略的同时,汾酒还顺势将女性市场纳入了年轻化的战略纵深。 文/每日财报 杜康 当前...
雷军2026两会准备5份建议:... 站长之家(ChinaZ.com) 3月4日 消息:今日,小米CEO雷军以全国人大代表的身份发文透露,...
电商模特图片怎么生成?AI模特... 作为商家或平台,在电商平台运营的过程中,我们经常会需要使用到一些带有模特的形象的产品图片进行产品宣传...
瑞幸大股东被传已买下蓝瓶咖啡 雀巢旗下高端咖啡品牌蓝瓶咖啡(Blue Bottle Coffee)的出售有了新消息。 3月4日下午...
2026化工基金投资指南:宏利... 2026年,化工板块不再是单纯的“周期代言人”。在供给端优化与需求端(AI、新能源、机器人)爆发式增...
库克秀刀法 苹果MacBook... 快科技3月5日消息,苹果公司正式发布了新款笔记本电脑MacBook Neo,起售价定为4599元。作...
从A股折戟到港股再战!沪鸽口腔... 2026年2月27日,港交所披露山东沪鸽口腔医疗集团有限公司(简称:沪鸽口腔)更新后的招股书,这已是...
佰维存储大宗交易折价成交17.... 佰维存储03月04日大宗交易平台共发生1笔成交,合计成交量17.90万股,成交金额3150.22万元...
全国人大代表、联泓新科董事长郑... 2026年全国两会召开之际,《每日经济新闻》记者获悉,全国人大代表、联泓新科(SZ003022,股价...
中东局势引爆油市!多家基金公司... 本文自南都·湾财社。 采写 | 南都·湾财社记者 罗曼瑜 编辑 | 柴华 2月28日以来,美以与伊...
年初业绩暴增9倍!佰维存储“2... 图源:图虫 3月4日,存储器概念逆势上涨。 Wind数据显示,存储器指数(8841241.WI)3月...
关于现货黄金,这几个说法你相信... 现货黄金在很多人脑子里,是一个带着点神秘气息的东西——像一块蒙着布的棋盘,看不清里面的规则,只能靠别...