shell参数传递与默认值
# 处理参数
几个特殊字符用来处理参数:
参数处理 | 说明 |
---|---|
$0 | 当前脚本的文件名 |
$n | 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。 |
$# | 传递到脚本或函数的参数个数 |
$* | 以一个单字符串显示所有向脚本传递的参数 |
$@ | 与$*相同,但是使用时加引号,并在引号中返回每个参数。 |
$$ | 脚本运行的当前进程ID号 |
$! | 后台运行的最后一个进程的ID号 |
$- | 显示Shell使用的当前选项,与set命令功能相同。 |
$? | 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。0是为正常退出,其他为不正常退出 |
退出状态码大体分两种:
- 一种是命令正确执行的状态码,该状态码为:0
- 一种是命令错误执行的状态码,为1-255
Linux退出状态码
状态码 | 描述 |
---|---|
0 | 命令成功结束 |
1 | 通用未知错误 |
2 | 误用shell命令 |
126 | 命令不可执行 |
127 | 没找到命令 |
128 | 无效退出参数 |
128+x | Linux信号x的严重错误 |
130 | 命令通过Ctrl+C终止 |
255 | 退出状态码越界 |
状态码取值范围为0-255,如果在指定的状态码大于255,那么shell会通过模(模就是256)运算得到相应的退出状态码。
# 默认参数(变量默认值)
# if
繁琐方式【要点】
注意这里有空格;
if [ ! $1 ]; then
$1='default'
fi
2
3
# if [ ! $1 ]; then
# isCache=false
# else
# isCache=$1
# fi
isCache=false
if [ $1 ]; then
isCache=$1
fi
2
3
4
5
6
7
8
9
示范:
#!/bin/bash
PRO_NAME=autorun-pro
PRO_VERSION=0.1.0
isCache=false
if [ $1 ]; then
isCache=$1
fi
if [ $isCache == true ]; then
docker build --no-cache -t $PRO_NAME .
else
docker build -t $PRO_NAME .
fi
2
3
4
5
6
7
8
9
10
11
12
13
14
# -
变量为null
取默认值
- 变量 为 null
${vari-defaultValue}
实践
[root@linuxidc /]# unset name
[root@linuxidc /]# echo ${name}
[root@linuxidc /]# echo ${name-samy}
samy
[root@linuxidc /]# name=""
[root@linuxidc /]# echo ${name-samy}
[root@linuxidc /]# echo ${name}
2
3
4
5
6
7
8
9
# =
变量为null时, 同时改变变量值
[root@linuxidc /]# unset name
[root@linuxidc /]# echo ${name=samy}
samy
[root@linuxidc /]# echo $name
samy
[root@linuxidc /]# name=""
[root@linuxidc /]# echo ${name=samy}
[root@linuxidc /]#
2
3
4
5
6
7
8
9
# :-
变量为null 或 空字符串
取默认值
- 变量为null
- 变量为空字符串
${vari:-defaultValue}
# :=
变量为null 或 空字符串, 同时改变变量值
{$vari:=defaultValue}
测试 null
[root@linuxidc /]# unset name
[root@linuxidc /]# echo ${name:=samy}
samy
[root@linuxidc /]# echo ${name}
samy
[root@linuxidc /]#
2
3
4
5
6
7
测试 空字符串
[root@linuxidc /]# name=""
[root@linuxidc /]# echo ${name:=samy}
samy
[root@linuxidc /]# echo $name
samy
2
3
4
5
# :?
变量为null 或 空字符串时报错并退出
[root@linuxidc /]# unset name
[root@linuxidc /]# echo ${name:?samy}
-bash: name: samy
[root@linuxidc /]# name=""
[root@linuxidc /]# echo ${name:?samy}
-bash: name: samy
[root@linuxidc /]# name="guest"
[root@linuxidc /]# echo ${name:?samy}
guest
2
3
4
5
6
7
8
9
# :+
变量不为空时使用默认值
与 :-
相反
[root@linuxidc /]# name="guest"
[root@linuxidc /]# echo ${name:+samy}
samy
[root@linuxidc /]# echo $name
guest
2
3
4
5
# $$使用
echo $$
29949
2
# 脚本参数
# $0,$1,$2..
优点:获取参数更容易,执行脚本时需要的输入少
缺点:必须按照顺序输入参数,如果中间漏写则参数对应就会错误
#!/bin/bash
echo "File Name: $0"
echo "First Parameter : $1"
echo "First Parameter : $2"
echo "Quoted Values: $@"
echo "Quoted Values: $*"
echo "Total Number of Parameters : $#"
2
3
4
5
6
7
运行结果:
$./test.sh samy zh
File Name : ./test.sh
First Parameter : Zara
Second Parameter : zh
Quoted Values: samy zh
Quoted Values: samy zh
Total Number of Parameters : 2
2
3
4
5
6
7
下面是参数超过10个的情况,在test.sh
文件写入
#!/bin/bash
echo "脚本名$0"
echo "第一个参数$1"
echo "第二个参数$2"
echo "第三个参数$3"
echo "第四个参数$4"
……
echo "第十个参数$10"
echo "第十个参数${10}"
2
3
4
5
6
7
8
9
在shell中执行脚本,结果如下
$ ./test.sh a b c d e f g h i j
#shell中将会输出:
脚本名./test.sh
第一个参数a
第二个参数b
第三个参数c
第四个参数d
第五个参数e
第六个参数f
第七个参数g
第八个参数h
第九个参数i
第十个参数a0
第十个参数j
2
3
4
5
6
7
8
9
10
11
12
13
14
可以看到${10}正确读取到了第十个参数,而$10被分成$1读取到第一个参数a然后拼接字符串0,于是输出a0。
# getopts【要点】
# bash 内置的 getopts;外部强大的参数解析工具:getopt
优点:由于使用了-a加参数值的方式进行一一匹配,所以不会参数匹配错误,同时也可以缺省参数,并不会导致参数错误,同时也便于后期参数的扩展和移植
缺点:脚本执行时参数需要的输入会增多
语法格式:getopts [option[:]] [DESCPRITION] VARIABLE
- option:表示为某个脚本可以使用的选项
- ":":如果某个选项(option)后面出现了冒号(":"),则表示这个选项后面可以接参数(即一段描述信息DESCPRITION)
- VARIABLE:表示将某个选项保存在变量VARIABLE中
同样新建一个test.sh
文件, 目前发现只能识别一个字母;
#!/bin/bash
while getopts "a:b:c:" opt; do
case $opt in
a)
echo "参数a的值$OPTARG"
;;
b)
echo "参数b的值$OPTARG"
;;
c)
echo "参数c的值$OPTARG"
;;
?)
echo "未知参数"
exit 1
;;
esac
done
echo "全部执行"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
用一个while循环加case分支获取不同参数,a:b:c
相当于定义参数的变量名,有时候可能会有未知参数,所以增加一个?的分支。
$ ./test.sh -a 1 -b 2 -c 3
参数a的值1
参数b的值2
参数c的值3
2
3
4
$ ./test.sh -a 1 -c 3
参数a的值1
参数c的值3
2
3
$ ./test.sh -a 1 -c 3 -d 4
参数a的值1
参数c的值3
未知参数
2
3
4
实践:
情况一:
#!/bin/bash
#选项后面的冒号表示该选项需要参数,没有设置的话,后面的$OPTARG获取不到参数;
while getopts "a:bc" arg
do
case "$arg" in
a)
echo "a's arg:$OPTARG" #参数存在$OPTARG中
;;
b)
echo "b"
;;
c)
echo "c"
;;
?) #当有不认识的选项的时候arg为?
echo "unkonw argument"
exit 1
;;
esac
done
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
运行:注意-b -c -bc
参数;
➜ bash sh ./test.sh -a arg -b -c
a's arg:arg
b
c
➜ bash sh ./test.sh -a arg -bc
a's arg:arg
b
c
2
3
4
5
6
7
8
其他例子:
#!/bin/bash
while getopts 'd:Dm:f:t:' OPT; do
case $OPT in
d)
DEL_DAYS="$OPTARG";;
D)
DEL_ORIGINAL='yes';;
f)
DIR_FROM="$OPTARG";;
m)
MAILDIR_NAME="$OPTARG";;
t)
DIR_TO="$OPTARG";;
?)
echo "Usage: `basename $0` [options] filename"
esac
done
shift $(($OPTIND - 1))
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
情况二:【推荐】
#!/bin/bash
echo 初始 OPTIND: $OPTIND
while getopts "a:b:c" arg #选项后面的冒号表示该选项需要参数
do
case $arg in
a)
echo "a's arg:$OPTARG" #参数存在$OPTARG中
;;
b)
echo "b's arg:$OPTARG"
;;
c)
echo "c's arg:$OPTARG"
;;
?) #当有不认识的选项的时候arg为?
echo "unkonw argument"
exit 1
;;
esac
done
echo 处理完参数后的 OPTIND:$OPTIND
echo 移除已处理参数个数:$((OPTIND-1))
shift $((OPTIND-1))
echo 参数索引位置:$OPTIND
echo 准备处理余下的参数:
echo "Other Params: $@"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
运行:
➜ bash bash getopts2.sh -a 1 -b 2 -c 3 test -oo xx -test
初始 OPTIND: 1
a's arg:1
b's arg:2
c's arg:
处理完参数后的 OPTIND:6
移除已处理参数个数:5
参数索引位置:6
准备处理余下的参数:
Other Params: 3 test -oo xx -test
2
3
4
5
6
7
8
9
10
情况三:【重点】
sh build.sh -c true -p true
PRO_NAME=autorun-pro
PRO_VERSION=latest
isCache=false
isPush=false
#选项后面的冒号表示该选项需要参数
while getopts "c:p:" opt; do
case $opt in
c)
echo "参数C的值$OPTARG"
isCache=$OPTARG
;;
p)
echo "参数P的值$OPTARG"
isPush=$OPTARG
;;
?)
echo "未知参数"
exit 1
;;
esac
done
if [ $isCache == true ]; then
docker build -t $PRO_NAME:$PRO_VERSION .
else
docker build --no-cache -t $PRO_NAME:$PRO_VERSION .
fi
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 输入参数默认【推荐】
其他参数详细见【06.shell参数传递与默认值】说明
#!/bin/bash
v=${1:-'1.0.0'}
h=${2:-'test demo'}
echo ${v}
echo ${h}
2
3
4
5
[root@samy ~]# bash test.sh
1.0.0
test demo
[root@samy ~]# bash test.sh abc 123
abc
123
2
3
4
5
6
# 默认参数
其他参数详细见【06.shell参数传递与默认值】说明
通常shell中我们需要给变量设置默认值,可能会写出如下代码
#!/bin/bash
if [ ! $1 ]; then
$1='default'
fi
2
3
4
显然这种方式在变量少的时候没啥问题,一旦变量多起来,我们可能就有大量的重复劳动(if判断)
有没有比较优雅的方式,不用写一大堆if判断,显然答案是有的
#当变量a为null时则var=b
var=${a-b}
2
# 函数参数
# 各个比较
#!/bin/bash
funWithParam(){
echo "第一个参数为 $1 !"
echo "第二个参数为 $2 !"
echo "第十个参数为 $10 !"
echo "第十个参数为 ${10} !"
echo "第十一个参数为 ${11} !"
echo "参数总数有 $# 个!"
echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
2
3
4
5
6
7
8
9
10
11
输出结果:
第一个参数为 1 !
第二个参数为 2 !
第十个参数为 10 !
第十个参数为 34 !
第十一个参数为 73 !
参数总数有 11 个!
作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !
2
3
4
5
6
7
# $* 和 $@ 的区别
$* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"$1" "$2" … "$n" 的形式输出所有参数。
但是当它们被双引号(" ")包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。
$*和$@详细区别请看此处
#!/bin/bash
echo "-----------------"
for key in "$@"
do
echo '$@' $key
done
echo "-----------------------------"
for key2 in $*
do
echo '$*' $key2
done
2
3
4
5
6
7
8
9
10
11
1、带引号执行及结果:
[root@localhost ~]# bash file.sh linux "python c"
-----------------
$@ linux
$@ python c
-----------------------------
$* linux
$* python
$* c
2
3
4
5
6
7
8
2、不带引号执行及结果:
[root@localhost ~]# bash file.sh linux python c
-----------------
$@ linux
$@ python
$@ c
-----------------------------
$* linux
$* python
$* c
2
3
4
5
6
7
8
9
# 函数返回值
两种方式
- 用变量接收函数返回值,函数用echo等标准输出将要返回的东西打印出来。
- 用 $? 来接收函数的执行状态,但是 $? 要紧跟在函数调用处的后面。
function getEnvConf() {
param=$1
echo $param
}
echo $(getEnvConf isPro) #可以返回字符串
#isPro
2
3
4
5
6
#!/bin/sh
function getStr(){
return "string"
}
#方法一
echo `getStr`
#方法二
echo $(getStr)
2
3
4
5
6
7
8
9
10
#!/bin/bash
function getResult(){
echo "这是我的第一个 shell 函数!"
return `expr 1 + 1`
}
getResult
echo $?
echo $?
2
3
4
5
6
7
8
输出结果:
这是我的第一个 shell 函数!
2
0
2
3
createDir.sh
创建目录
#!/bin/bash
function createDir(){
if [ ! -d $1 ]; then
mkdir -p $1
fi
}
DIR="temp/"
# 两者二先一
#$(createDir $DIR)
$(createDir "temp/")
2
3
4
5
6
7
8
9
10
11
# for跟case的配合使用
all.sh
#!/bin/bash
buildAdmin() {
echo "buildAdmin"
}
buildWeb() {
echo "buildWeb"
}
buildCapacity() {
echo "buildCapacity"
}
buildFiles() {
echo "buildFiles"
}
if [ $# -gt 0 ]; then
for i in "$@"; do
case $i in
admin | a)
buildAdmin
;;
web | w)
buildWeb
;;
capacity | c)
buildCapacity
;;
files | f)
buildFiles
;;
*)
echo "Ignorant"
;;
esac
done
else
echo 'all pro build'.
fi
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
➜ build-sh ./all.sh a w c f
admin
web
capacity
files
➜ build-sh ./all.sh
all pro build.
2
3
4
5
6
7
参数时区处理:
param=zh
datePath=app/utils/date-utils.js
varKey=defaultTz
timeZone='Asia\/Shanghai'
# 初始化默认中文
sed -i "" "s/\($varKey =\).*/\1 '$timeZone';/" $datePath
echo "参数的值$1"
if [ $1 ]; then
param=$1
case $1 in
zh)
timeZone='Asia\/Shanghai'
;;
en)
timeZone='America\/Los_Angeles'
;;
eu)
timeZone='Europe\/London'
;;
*)
echo "param not found!!"
exit 1;
;;
esac
sed -i "" "s/\($varKey =\).*/\1 '$timeZone';/" $datePath
fi
echo "param参数的值$param"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
调用:
sh start.sh
sh start.sh en
2
3
# 参考链接
https://www.runoob.com/linux/linux-shell-func.html
https://blog.51cto.com/steed/2443313