shell-不定参数

这两天在写shell脚本,因为接到了王老板的安排。先是让我写了个触发器,然后就是将之前别人的脚本优化一下。其实我来这里没多久就把那个脚本重写了,因为之前的那个输出真的很乱,看的我眼睛疼。虽然已经有现成的了,但是距离王老板的要求(简洁、输出重要信息、屏蔽没有的信息),我自认为还差点意思。

刚开始让我写个触发器的时候,我一脸懵,触发器是啥?然后王老板给我找了个别人写的模板,让我对着学一下。哈哈,怕给我压力,然后叫我随便玩一下,说也不重要。这么长时间了,觉得王老板这个人挺好的,等我以后离开这个地方后,我觉得真的还挺舍不得的。学了之后发现和存储过程一样简单,然后一会就写完了,因为之前学了存储过程,里面涉及取变量的操作,做起来就觉得挺简单的。不过用到了一个新的函数sys.guid()用来生成唯一的标识符,为了避免重复操作导致不能辨别嘛。

然后就是改这个shell脚本了,之前我改了一下,主要是改格式,之前输出没对齐,看着特别乱。然后加了一些上限值的警告,如果正常的话,会在后面输出bingo!哈哈。但是还是会在屏幕上输出很多信息,也就是刷屏了。然后就是这个上限警告值是写死在里面的,所以这次优化,主要是加入这些功能:

  1. help信息
  2. -s 数字 来设置size的上限
  3. -m 数字 来设置数量上限
  4. -q 来设置quiet/silent模式,即不刷屏,只显示最后结果。当然想看这些信息的话,就不加这个参数咯

两个点:

  • 所有这些都需要通过参数传递进去
  • 但是如果没传参数也要有默认值

不用if判断的赋值

:- or- 如果值为空则赋值

:+or+ 如果值非空就赋值

也可以理解为赋默认值,其实本意是先判断再赋值。按照原意理解的话,就可以省去一个if判断变量是否为空的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
${variable:-值}
#or
${variable-值}
eg:
${a:-2} #a为空则赋值2
${b-3} #b为空则赋3

${variable:+值}
#or
${variable+值}
a=10;b=20
${a:+2} #a值不为空,则赋值2
${b+2} #b值不为空,则赋值2

三目运算

程序写多了,才会发现这些语法的重要性。就好比python的lambda函数,对于一些简单的函数来说简直是好用。这里要说的是shell中的三目运算,其实好多if判断很简单,仅仅是做一个判断加一个赋值,有时候就觉得真的没必要写一个if...then....fi出来。但是可惜的shell的三目运算仅仅支持数字。

1
2
3
4
5
6
# a是否为20,是返回1,否则返回2
$((a==20?1:2))

a=20
#将返回值赋值给c
c=$((a==20?1:2))

shell中传参

我之前想的是把所有传递进去的参数作为一个列表或者字符串。因为一个参数后面要跟一个数字,为了取到这个数字,我用的是字符串截取。因为我用shift老是取不到想要的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
list=$*
for i in $*
do
case $i in
-s)
#字符串截取,将左边到-s的字符(包括-s)全部忽略
size=`echo ${list#*-s} | awk '{print $1}'`
;;
-m)
number=`echo ${list#*-m} | awk '{print $1}'`
;;
-h | --help)
echo "help manual"
;;
*)
;;
esac
done
#如果传入参数为空就赋值
echo ${size:-888}
echo ${number::666}

上面这么写没问题,本来我之前想用shift取参数的,毕竟学过perl嘛,perl就是这么做的,但是我没成功。

是我太愚蠢了:),我每次都是shift一个参数,结果第二个参数就要shift两个,第三个参数又只要shift一个参数。如果传入参数的顺序不变,那没问题。但是。。。。。。谁能保证参数顺序不变,而且程序也不能设计的这个样子吧,我自己都看不下去了。所以傻傻的我google到了正确写法:一次shift两个参数 shift 2

虽然我不知道可以一次可以shift两个参数,但是我想都不敢想,说明我傻。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
for i in $*
do
case $i in
-s)
size=${2:-888}
#一次shift两个参数,将-s和它的数字都去掉了。后面的就一样了
shift 2
;;
-m)
number=${2:-666}
shift 2
;;
-h | --help)
echo "help manual"
;;
*)
;;
esac
done
echo $size
echo $number

这么写多帅啊,不需要字符串截取,不需要awk,不需要子进程,速度也快多了。

shift说了这么多,还没写它的作用,它就好比从栈中(pop)取数据。不过是从左边取,不带参数的话就是一次取一个参数,取出来的参数是不会放回去的。不过poppush可以放回去,但是shell中shift为什么没有unshift呢?perl中就有啊。


不可例外的,还是要写一下这几天的总结:也算是过失吧

第一个:在写shell脚本的时候,因为要重复调用两次相同的代码,所以我就想着用一个函数写吧,这样简单不少。但是我却没考虑到写成了函数之后,它中间的变量问题。如果在函数外已经定义了变量,那好,一点问题都没有。但问题来了,他那个代码中竟然需要接受一个程序外部传进来的参数$1,所以始终是运行不正常的。后来才发现了这个问题,对于shell函数来说,$1代表的是传给函数的第一个参数:例如

1
2
3
4
function getvar(){
echo "$1 is the args of function"
}
getvar 666

最终这个$1接受到的就是666。所以它接受的并不是函数外部传进来的参数。所以这个教训的总结就是变量如果是从程序外部传进来的,二话不说先把这些变量保存下来,所有的都保存也好$*或者$@,一个一个的保存也好$1,$2。这样就不会出现这个问题了,这也算是一个良好的编程习惯吧。

第二个:如果是改写别人之前写的脚本,不仅要把自己的那部分功能实现,还要弄清楚别人之前写的意图,因为你改了之后就不能保证别人的还一样正确啊,比如说shell环境问题,变量问题,如果是函数的话还要考虑函数位置问题,各个模块的逻辑问题等等。总之不要只看自己写的那部分,就可以提高正确率,减少不必要的纠错时间。