前言
首先,我敢肯定,你必然能像大牛一样用shell完成N次递归。那么,有人就问了,递归是什么?递归,就是在一个程序里调用程序本身。那又有人要问了,这个递归该怎么样去完成呢?且慢,要想知道它是怎样完成的,就往下去看一看吧。
方法
在完成递归之前,我们先要知道linux中的shell中的$0参数,这个$0参数呢,跟参数$1 $2 $3等看起来没有一点用处,大多数就只是指向用户执行的shell可执行文件的地址,不能是一个数字,也不能是一个字符串,多局限啊。
虽然,参数$0的缺点是这样的,但是,它还有这样一个优点——便于递归,你想,假如如果不用参数$0,递归的代码是这样的:
/root/dg.sh `expr $1 + 1`
那么,当root管理员将这个dg.sh可执行文件移动到别的地方或者改个名时,这个dg.sh文件就报错了,非常的不安全啊。因此,这段递归的代码的前面如果不用$0参数来递归的话,也就不安全了。
而如果将这段代码前面的/root/dg.sh改为$0参数的话,那么只要该文件存在,照样能够运行。因此,实际这段代码长这个样子。
$0 `expr $1 + 1`
那么,为什么这段代码中的看似无用的参数$0却能够便捷的进行递归的操作呢?是因为当用户执行这段代码的时候,$0指向了用户所执行的包含这段代码的可执行文件。此时,就可以再次调用这个包含这段代码的可执行文件,以此来达到一种递归的效果。
因此,这就是看似无用的参数$0能够便捷的进行递归的操作的原因。现在,你只要执行一下这段代码,就已经完成了递归。现在,我们可以根据这样子的递归代码创作出别样的while循环代码了,比如这样:
#!/bin/bash
if [ 0 -lt $2 ]
then
echo $1
$0 $1 `expr $2 - 1`
fi
当然,你也可以完成这样的打印宽为5的长方形的程序代码:
#!/bin/bash
if [ 0 -lt $1 ]
then
for i in {1..5}
do
# 不换行
printf '*'
done
# 换行
echo
$0 `expr $1 - 1`
fi
需要注意的是,如果递归的次数过多,那么你将会看到这样的一个警告:
当你看到这样的警告时,就说明你的程序递归的次数过多了,也就是说系统递归中的shell程序的层级过高了,超过了1000层。这时,shell的系统就会把递归中的shell程序的层级数改为1。
因此,这可能会导致表示递归中的shell程序的层级数的$SHLVL环境变量1的错误,从而可能因此引发出bug来。比如这样的程序:
#!/bin/bash
echo $1
if [ $1 -le 2000 ]
then
$0 `expr $1 + 1`
fi
echo "end$SHLVL"
这是一个在该程序几千次递归结束后会打印出递归中的shell程序的层级数的程序。在执行它并且递归结束的时候,却会打印出这样的内容:
从中,我们可以看到表示递归中的shell程序的层级数的$SHLVL环境变量的值错了。因此,递归固然好,但过多递归不好。我们应当把减少递归的次数控制在几百以下才行。
总结
只需要用shell中的$0参数,就可进行递归操作。因为$0参数指向了用户所执行的程序文件,通过$0参数,可以再次执行用户所执行的可执行文件,所以可以进行递归操作。但需要注意的是,不要使递归的次数过多,因为这会导致表示递归中的shell程序的层级数的$SHLVL环境变量的错误,从而可能因此引发出bug来。
下篇预告
黑马都没教过的MySQL窗口函数,我1篇博客就给你讲得比黑马更清楚!
Footnotes
-
选自ken2232的CSDN博客Bash 中 SHLVL 变量为 1000 的时候 ↩