小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。
前言
shell 是 Linux 系统中,位于用户与内核之间的桥梁,shell 将用户的命令解析之后传给内核进行运行。
shell 是解释式语言,与其他高级语言C++、Java、Python等功能不强大,但是也支持编程的相关的操作,如定义变量、数组、字符串等,还支持函数、结构语言if...else,while等
我们已经学习对shell脚本学习了两期内容:
-
shell脚本工作原理浅析中对shell脚本工作方式及类型进行了解和学习。
-
shell脚本语法入门对shell 变量、数组、状态码等入门语法等学习
本期,我们将继续对shell 进阶的语法如函数知识等学习,Let's go~
1. 函数的定义和调用
shell 函数的本质是一段可以重复使用的脚本代码
shell 函数定义有3种方法:
- 方式一:
function
是shell 函数定义的关键字
function first_func_demo()
{
echo "函数的定义就这样了..."
}
- 方式三:带了 function 关键字,可以省略函数名可省略括号
function second_func_demmo
{
echo "函数也可以这么定义..."
}
- 方式三:可省略function关键
third_func_demmo()
{
echo "函数也可以这么定义..."
}
shell 调用函数
#!/bin/bash
first_func_demo
second_func_demo
third_func_demmo
shell 定义函数与Python一样简单,一秒就会。
如果要向函数传递参数,又如何呢?
shell 函数传参 以 函数名 参数1 参数2 ...
形式来进行的
shell脚本函数里头有奇奇怪怪的名字如:
$0
、$1
、$2
一直到$n
、$@
、$*
、$#
...
emmm,别慌,总结在下面:
$0: 表示程序名
$1...n:表示第1个...第n个参数
$#: 表示输入参数的个数
$@: 获取传入的参数数组,可用于for循环遍历处理场景
$*: 把所有命令行参数当做一个整体
那我们继续上面的脚本,向函数传递两个参数,演示如下:
function func_demo
{
echo "调用函数时传递参数以及读取参数就这么简单..."
# 读取第一个参数值
echo $1
# 读取第二个参数值
echo $2
# 读取总数
echo $#
}
# 1) 向函数传递两个参数,如果参数更多,空格分界,以此类推...
num1=10
num2=100
func_demo $num1 $num2
直接复制上面的代码跑一下吧,又是一秒就会。
2. 函数的返回值
shell 会把函数当作一个小型脚本,运行结束时会返回一个状态码。
默认情况,函数的退出状态码是函数中最后一条命令返回的退出状态码。
但这样你就无法得知函数里头的代码是否都被正确的执行,因此可以借助shell脚本的函数返回值
shell 函数返回值有两种方式:
- return语句
shell 函数返回值,可以借助return语句来进行返回值。
return 只能返回整数值
function func1 {
result=200
return $result
}
func1
echo "func1 run result: $?"
- echo输出来返回函数值
echo 可以返回任何数据类型的数据
function func2 {
result=200
echo $result
}
echo "func2 run result: $(func2)"
3. 在.bashrc文件中定义函数
shell 每次启动时会重新载入.bashrc
(ps:Mac是用zsh,所以是.zshrc,为了名字通用,我们都先同意叫bashrc吧)
bashrc 文件一般放在/home/linux用户名下,我们可以定义自己工具类函数,用于处理日常一些繁琐的工作流程,使其自动化。
这里举两个栗子吧:
1.比如每天都要更新所有的git仓库并进行备份;
2.常常很多命令没记错,比如dumpsys package、meminfo、activity,am,pm等等以及其他串口命令,可以自定整理一份文档之后,之后通过调用函数直接打印这些常用命令
下面开始演示,我就定义个简单的栗子吧,在Mac中.zshrc文件中添加:
# 在.zshrc追加函数
function addem {
echo $[ $1 + $2 ]
}
重启zsh终端,然后运行试试:
$ addem 10 20
30
4. 命令行参数的处理
上面学习了调用函数如何输入参数和读取参数。
那如果执行某个脚本文件或者执行某个命令行的参数输入、读取呢?
其实跟函数参数的输入、读取基本一致,直接上小结吧
1.命令行参数的读取,$0:程序名,$1,$2...表示第一个、第二个参数依次类推
2.特殊参数变量:$#(返回命令参数的个数)
3.获取所有命令行参数:$*(把所有命令行参数当做一个整体)、$@(获取命令行数组,主要用于for循环)
这3点问题不大,直接上个小demo演示,juejin.sh脚本内容如下:
#!/bin/bash
echo $0
echo $1
echo $2
在终端执行juejin.sh脚本结果演示:
$ sh /Users/xxx/Desktop/juejin.sh HaHa 123
/Users/xxx/Desktop/juejin.sh
HaHa
123
5. 命令行选项的处理
命令行选项也没什么特殊的。
在命令行上,它们紧跟在脚本名之后,就跟命令行参数一样。
实际上,如果愿意,你可以像处理命令行参数一样处理命令行选项。
选项是跟在单破折线后面的单个字母,根据不同的选项执行不同的逻辑,有点像switch语句。juejin.sh演示脚本如下:
#!/bin/bash
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found -a option" ;;
-b) echo "Found -b option" ;;
*) echo "$1 option not found" ;;
esac
shift
done
在终端执行juejin.sh脚本并输入选项试试:
$ sh juejin.sh -a -b -c -d
Found -a option
Found -b option
-c option not found
-d option not found
那命令行参数和命令行选项同时用呢?
通过双破折线(--)来实现参数和选项的分离。
shell会用双破折线来表明选项列表的结束,在双破折线之后,脚本就可以放心地读剩下的命令行参数了,而不是当选项处理。
#!/bin/bash
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found -a option" ;;
-b) echo "Found -b option" ;;
--) shift
break ;;
*) echo "$1 option not found" ;;
esac
shift
done
count=1
for param in $@
do
echo "Param: $param"
let count+=1
done
我们执行上面的juejin.sh脚本,并传入选项参数、命令行参数,得到执行结果如下:
$ sh script.sh -a -b -c -d -- HAHA 123
Found -a option
Found -b option
-c option not found
-d option not found
Param: HAHA
Param: 123
那如果有些选项参数需要传值呢?
我们在继续基于上面的脚本修改:
#!/bin/bash
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found -a option" ;;
-b) param_value="$2"
echo "Found -b option with value $param_value"
shift ;;
--) shift
break ;;
*) echo "$1 option not found" ;;
esac
shift
done
count=1
for param in $@
do
echo "Param: $param"
let count+=1
done
脚本修改之后的执行结果:
$ sh juejin.sh -a -b ss -c -d -- HAHA 123
Found -a option
Found -b option with value ss
-c option not found
-d option not found
Param: HAHA
Param: 123
6. getopt命令
有时候我们需要合并选项参数,比如这样的格式:
$ sh juejin.sh -ab
getopt命令可以接受一系列任意形式的命令行选项和参数,并自动将它们转换成适当的格式。
getopt的命令格式如下:
getopt optstring params
optstring:是关键所在,它定义了命令行所有需要输入的选项参数字母,如果选项参数需要带值,则在对应的字符后面加冒号(:)
有点绕?我们用上面在终端运行的脚本作为栗子:
$ sh juejin.sh -a -b ss -c -d -- HAHA 123
一眼就看到juejin.sh脚本的选项参数有,abcd,其实b还带参数值,
那如果用getopt命令来处理后面这一大串选项、参数会是怎样的呢?
我们在终端尝试运行下面的命令:
$ getopt ab:cd -a -b ss -cd HAHA 123
-a -b ss -c -d -- HAHA 123
在命令选项的工作机制之后,假设我们以后想了解某个命令行怎么用?可以怎么做呢?还是做个demo吧:
function read_params
{
while [[ -n $1 ]]
do
case $1 in
-a) echo "Found option -a" ;;
-b) echo "Found option -b"
echo "Value is $2"
shift ;;
--) shift
break ;;
*) echo "Option not found" ;;
esac
shift
done
count=1
for param in $@
do
echo $param
let count+=1
done
}
read_params `getopt ab: $*`
然后在终端就可以:
$ sh juejin.sh -ab HAHA 123 456
7. 总结
本期,继续对shell语法之函数进行学习,shell 语言虽然不像高级语言那样强大,但是作为程序语言,也具有高级语言基本特点。
函数本质就是把重复代码进行封装,可以进行重复使用
在shell脚本中,我们可以把实现具体的功能,使用函数封装起来,后续可以方便的进行调用使用
以上是本期内容,欢迎大佬们点赞评论,下期见~♥️