《学习bash》笔记--命令行选项和有类型变量

1.命令行选项

如果有一个shell脚本处理命令teatime alice hatter,那么$1就是“alice”,$2就是“hatter”。如果命令为teatime -o alice hatter,

则$1就是-o,$2为“alice”,$3为“hatter”。

可能你会认为要编写以下代码来处理参数:

if [ $1 = -o ];then

 处理-o选项的代码

 1=$2

 2=$3

fi

对$1和$2的正常处理...

此代码有希望问题,首先,声明1=$2是非法的,因为位置参数是只读的。即使是合法的,出现的另一问题是这样的代码对

脚本可以处理的参数个数强加了限制--这样做是不明智的。另外,如果此命令有几个可选项,处理他们的代码经很快变得

很混乱。


1.1.shift

shell提供了解决此问题的方式,命令shift执行功能:
1=$2
2=$3
....
如果你向shift给出了数值,它可以重复移位参数。例如shfit 3产生的效果是:
1=$4
2=$5
....

例如a.sh的内容如下:
if [ $1 = "-o" ] && [ $2 = "-e" ]; then
echo "option -o && -e found"
shift 2
echo "$1"
echo "$2"
fi
执行结果:
$ ./a.sh -o -e 1 2
option -o && -e found
1
2

1.2.getopts

上述代码不允许用户将多个参数和单个短划线结合,即不允许用-abc表示-a -b -c,也不允许指定在选项和参数见没有空格的情况,
即不允许-barg,而必须是-b arg。
getopts带有两个参数,第一个是包含字符和冒号的字符串。,每个字母均为有效选项,如果字母后跟一个冒号,则选项需要一个参数。
getopts从命令行中抽取选项,将其赋给一个变量,变量名时getopts的第二个参数,只要还有选项需要处理,getopts就返回退出状态
0,一旦选项处理完毕,则其返回状态1,使得while退出。
如果有一个命令的格式如下:
alice [-a] [-b arg] [-c] arg1 arg2
那么使用getopts可以实现,alice的脚本内容如下:
while getopts ":ab:c" opt; do
case $opt in
  a) statements;;
  b) statements, OPTARG is the option argument;;
  c)statement;;
  \?) echo "usage:alice [-a] [-b arg] [-c] arg1 arg2"
    exit 1
esac
done
shift (($OPTIND - 1))
process of arguments
while条件下对getopts的调用建立循环以接受选项-a,-b和-c,并将-b带有一个参数,每次执行循环体时,代码都会使opt中不带短划
线的最新选项可利用。如果用户键入无效选项,getopts正常情况下打印一个错误信息(针对格式:cmd:getopts:illegal option -o),
并将opt设置为?。如果字符串起始处有一个冒号,getopts不会打印该信息。
在while循环中不再有shift语句:getopts不依赖shift以了解其位置,在getopts完成前,即while循环退出前,移动参数是不必要的。
如果选项带一个参数,getopts将其保存在变量OPTARG中,它可用于处理选项的代码中。
最后一个shfit语句在while之后,getopts在变量OPTIND中保存了要处理的下一个参数的位置数。例如,如果命令行为alice -ab rabbit,
则$OPTIND为3,如果命令行为alice -a -b rabbit,则$OPTIND为4。

例如a.sh的内容如下:
while getopts ":ab:c" opt; do
case $opt in
a) echo "option -a found";;
b) echo "option -b found,arg is $OPTARG";;
c) echo "option -c found";;
\?) echo "usage:a.sh [-a] [-b arg] [-c] arg1 arg2"
exit 1
esac
done
shift $(($OPTIND-1))
echo "arg1:$1,arg2:$2"
执行结果:
$ ./a.sh -a -b 1 a1 b1
option -a found
option -b found,arg is 1
arg1:a1,arg2:b1

$ ./a.sh -a -c a1 b1
option -a found
option -c found
arg1:a1,arg2:b1

$ ./a.sh -a a1 b1
option -a found
arg1:a1,arg2:b1

2.有类型变量

可以使用declare内置命令设置变量属性。下面总结了declare选项,-打开选项,+关闭选项。在当前提示符下键入declare
会显示所有的变量和函数定义。
-a
将变量看成数组

-f
只显示函数名,如果执行declare -f,显示所有函数的定义;如果执行declare -f funcname,显示funcname的定义。

-F
显示所有的函数名

-i
将变量看做整数,定义为整数的变量可以直接使用运算符进行运算,而不需要$(())或者(())操作符。
例如:
i=1
j=2
k=i+j
echo $k
执行结果为:
i+j
将k=i+j修改为declare -i k=i+j以后,执行结果为:
3

-r
使变量只读,和readonly命令功能一样。

-x
将变量作为定义为环境变量,同export。

3.整数变量和运算

bash将$(())包围的单词解释为算术表达式。算术表达式内的变量前面不需要加美元标记,虽然加上也没错,例如:
$((1+2))将返回3
在bsh中通过外部命令expr才可使用:
expr 1 + 2将返回3。注意:运算符两边必须要有空格。

下面给出bash支持的算术操作符。
+:加
-:减
*:乘
/:除
%:取余
<<:左移位
>>:右移位
&:位与
|:位或
~:位非
!:位非
^:位异或

执行算术运算还可以使用((...)),但是有如下问题,例如下面的脚本:
i=1
((i=i+1))
echo $i
执行结果正确,为2.
但是修改为:
$((i=i+1))
虽然执行结果也为2,但是会报错,具体原因不明,我使用的bash版本为4.2.8。
修改为:
i=((i+1))
执行结果为1,而且也会报错。
修改为:
i=$((i+1))
执行结果正确,为2.

算术表达式也支持关系操作符,真值为1,假值为0,下面给出了关系操作符:
<:小于
>:大于
<=:小于等于
>=:大于等于
==:等于
!=:不等于
&&:逻辑与
||:逻辑或
例如:$((3<2))值为0,$(((3>2)||(4<=1)))值为1

shell还支持N进制,这里N从2到36,表达式B#N表示B进制数N。如果省略了B#,则默认为10进制。
例如:echo $((2#1010))结果为:10

3.1.算术条件

之前我们说明了使用[...]比较字符串大小,但是必须使用自己的操作符执行,如[ 3 -gt 2 ],产生状态0.
另一种进行算术测试的方法是使用$(())形式来封装条件。例如:
[ $((2>1)) = 1 ]
此表达式对条件进行求值,然后比较结果值为1.

3.2.算术变量和赋值

前面介绍的,你可以通过declare定义整数变量,也可以对算术表达式求值并使用let将之赋值给变量。语法为:
let intvar=expression
在let语句中没有必要将表达式括在$(())中,let使得后跟在等号后面的表达式被解释为一个算术值。
将表达式用引号括起来是个很好的喜欢,因为很多字符都被shell看做特殊字符,例如#,*,#以及圆括号,另外
必须将包含空白的表达式引起来。

4.数组

给数组赋值,有几种方式,最直接的方式是像其他变量一样使用赋值语句:
name[2]=a
name[0]=b
name[1]=c
另一种赋值方式时使用一个复合语句:
name=([2]=a [0]=b [1]=c)
实际上,如果稍微重排一下次序,甚至不必给出下标:
name=(b c a)
bash自动将取值赋给从0开始的顺序元素。如果在复合赋值语句中某处给出下标。则从该点连续设置取值。
例如:name=(a b [3]=c d),则数组的内容为:a b 空 c d,一共5个元素。
数组以这种赋值形式自动创建,要创建一个空数组,可以使用declare -a array命令。
数组中的一个元素可用语法${array[i]}引用。如果不给出下标,则假定为数组元素0。
还可以使用特殊下标@和*,它们返回数组中的所有元素取值,其工作方式与位置参数一致。这在使用for循环取值时非常有用:
for i in “${name[@]}”; do
  echo $i
done
未被赋值的任何数组元素均不存在,默认为null字符串。
例如:
name=(a [2]=b [3]=c)
for i in “${name[@]}”; do
  echo $i
done
运行结果:
a
b
c
而不是
a

b
c

对数组有用的一个操作符是#,即长度操作符,要找出一个数组中任意元素的长度,可以使用${#array[i]}.
要找出数组中有多少个取值,则使用*或者@做下标,需要注意的是,空元素不算在数组取值数中。

使用一个复合语句对已有的数组重新赋值会将该数组替换为新值。所有的旧值均失效。例如上面的name数组重新赋值为
([100]=a b c),则下标为0,1,2等的取值会消失。

可以使用unset内置命令销毁任意元素或整个数组,如果指定一个下标,则特定元素被销毁(该元素被设置为null,后面的元素
下标不变),例如:
name=(a b c d)
unset name[1]
echo “${name[0]}”
echo “${name[1]}”
echo “${name[2]}”
echo “${name[3]}”
执行结果:
a

c
d
而不是
a
b
c
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值