- 9
- Sep
“盗梦空间(Inception)”刚刚在国内上映那会(2010年9月1日)我就去看了,确实是一部好电影。后来还在网上看到说盗梦空间就像是一层层的“函数调用”,确实很形象(见此:Inception:一场层层调用的函数大战)。
今天看推时,突然看到一条,说是Shell有个变量:$SHLVL,是查看当前Shell的级别(Level)。我立马一试,果然如此,简直就是Inception的翻版!
我们在使用Shell(以Bash为例)的过程中,实际上就是一个Inception的过程:执行一个脚本的时候,并不是在当前的Shell环境下执行的,而是另起一个Shell,在里面执行,执行完毕后,销毁它,并回到当前的Shell。
一般情况下,我们的Shell都是第一层,如图:
如何进入下一层呢?只需要不停地执行自身(bash)即可,如图,执行了三次bash后,成功进入了第四层Shell:
与Inception一样的是,想要回到前一层,必须得执行“exit”完成任务,或者被“kill”。假如很不幸第一层被kill掉的话,后面的N层梦境都没有了(父进程退出,子进程也遭殃)。
问题来了:Shell到底支持几层梦境呢?在看了Bash的源码后,我发现它竟然支持1000层!在Bash源码的variables.c,约4680行左右中有这样的定义:
if (shell_level < 0)
shell_level = 0;
else if (shell_level > 1000)
{
internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level);
shell_level = 1;
}
也就是说,超过1000层后,又回到第1层,也就是现实世界了?
于是我就想进入1000层看看,如何方便的进入第1000层Shell呢?for loop一次次套一个bash命令肯定是行不通的,因为在进入下一层Shell后,上层的Shell的命令就不再对这层起作用了。
我想了很多方法都行不通,最后只好去请教神通广大、无所不能的华主席(@shellexy)。华主席就是牛逼,马上就给了一个解决方案,用Pygtk来Inception至N层!
原理是这样的:
使用GTK+的vte库来创建一个虚拟终端,通过vte.Terminal的paste_clipboard方法,不停地注入“bash \n”,于是该Terminal就能按照你想要的方式进入N层梦境了。源代码如下:
#!/usr/bin/python
import vte, gtk
window = gtk.Window()
window.set_default_size(480, 320)
window.set_title('Inception')
window.connect('destroy', lambda *w: gtk.main_quit())
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
term = vte.Terminal()
term.set_emulation('xterm')
sw.add(term)
window.add(sw)
window.show_all()
term.fork_command()
clipboard = gtk.Clipboard()
for i in range(1000):
clipboard.set_text('echo $SHLVL \n bash \n')
term.paste_clipboard()
gtk.main()
代码很简单,基本上不需要讲解。关键的便是clipboard的剪贴版操作及terminal的粘贴动作。
不过,如果你想真正进入第1000层,可是有点难的。这要取决于你的电脑是否有够强劲的CPU,是否有足够的内存——当然还有你是不是有足够的耐心。
在我的电脑上,我跑了很久……基本上是这篇日志开始写的时候开始跑的,一直到日志写完,还只有进入第三百多层,接下来每一层的进入都会花很多的时间,可以说是越来越慢。同时,我的物理内存(2GB)已经消耗完毕,开始烧SWAP了。
来两张图吧,壮观的“盗梦终端”:每一层都在“do_wait”下一层的完成……
pstree命令的效果:bash-bash-bash……实在是显示不过来了。
写完这篇日志时,我已经Inception至四百多层了,SWAP大概还有1700MB,看似可行,不过同时我的机器反应速度也越来越慢了,我还是先把日志发表了吧~
操作系统的世界,还真是跟现实相当类似啊。当然操作系统世界要比当前人类世界领先多了,比如fork(),哈哈。
我在想,要不大家来一个Inception至一千层的比赛,看谁的机器比较给力,能在最短的时间进入呢?
UPDATE-2010-09-10
发现rem1x兄提供的利用.bashrc进行Inception的方式相当棒。在此补充一下:
在$HOME目录下建立一个inception.sh,内容为:
echo "Level $SHLVL"
if [ $SHLVL -eq 999 ]; then
echo "e n d: `date +%H:%m:%S`"
else
bash
fi
然后再往 $HOME/.bashrc 中加入这么一段:
if [ "$SHLVL" -eq 1 ]; then
echo "start: `date +%H:%m:%S`"
fi
echo "Level $SHLVL"
./inception.sh
接下来开启一下全新的终端,然后它便开始不停地Inception至下一层了!




妳好蛋疼。。。
= =沙发
偷懒一下……
jimmy@jimmy:~$ export SHLVL=1000
jimmy@jimmy:~$ bash
bash: warning: shell level (1001) too high, resetting to 1
jimmy@jimmy:~$
学习了
加在.bashrc里面:
if [[ $SHLVL -le 1000 ]];then
bash
fi
我看我6G内存能撑得住么
inception.sh:
echo "Level $SHLVL"
if [ $SHLVL -eq 999 ]; then
echo "e n d: `date +%H:%m:%S`"
else
bash
fi
-------------华丽分割线--------------
我的猥琐方法......
.bashrc :
if [ "$SHLVL" -eq 1 ]; then
echo "start: `date +%H:%m:%S`"
fi
echo "Level $SHLVL"
./inception.sh
-------------输出分割线---------------
start: 22:09:34
Level 1
Level 2
Level 3
...
...
...
Level 999
e n d: 22:09:58
也忒能折腾了。。。1G内存就不做测试了。。。
fedora13 不慢啊 (偶2G 的内存) 运行完,发现少了620M 内存
$ time python 1.py
real 0m49.350s
user 0m2.348s
sys 0m0.331s
不过要注意ulimit -u,默认1024, 不设置会提示资源不可用,设置成3000就可以了
我一直用SHLVL判断是source还是bash。
把X关了
"当然操作系统世界要比当前人类世界领先多了"这话可不对,人类世界可以制造OS,OS可以制造人类世界吗?
每一个宇宙分支不就是执行了一次fork()吗
楼主的机子或者程序有问题,我手动进入328层shell的时候,没有用什么CPU,内存也才250M。进入1000层也消耗不了多少吧。
基本上进入多少层shell就相当于开了多少个terminal
用个省资料的终端会快些吗?在字符模式下能达到应该快些吧。
笑死我了 :)
牛!
单纯想耗内存的话这样快点,一样开了很多bash,但是$SHLVL数值不增加
#!/bin/bash
inc (){
(sleep 0.1;inc)
}
inc
真想死的把sleep也去掉……
创建一个电子表格文档, A1写bash, 拖动操作点至第999行. 全选, 复制, 粘贴到终端.
[root@SERVER /home/web]# bash
[root@SERVER /home/web]# bash
[root@SERVER /home/web]# echo $SHLVL
999
[root@SERVER /home/web]#
last pid: 20843; load averages: 0.00, 0.00, 0.00 up 6+00:21:31 18:25:09
1070 processes:1 running, 1069 sleeping
CPU: 100% user, 0.0% nice, 0.0% system, 0.0% interrupt, 100% idle
Mem: 1082M Active, 580M Inact, 620M Wired, 128K Cache, 809M Buf, 5435M Free
8G内存表示压力不大.
直接递归bash脚本都行啊,几乎不占资源的。的确到了1000就重1开始了。
真够疯狂的啊。。。
我是从图卦上看来的
图片水印是个好东西
如此我才晓得Tualatrix有了新文章
那个 pygtk 脚本慢的原因是因为操作是阻塞的,
主席开个子线程,控制下时间间隔,就能改善了
也就是说,超过1000层后,又回到第1层,也就是现实世界了?
这个表述是错误的。第1001层虽然叫做第1 层,但是和你开始时候的第1 层是不一样的。俺在俺的机器上试过了。
很深奥哦~没有看懂
成了硬件性能测试脚本了……
Mac OS 上进到250层就不行了好像, 我的方法就是在.bash_profile里加了一条:
bash -l
echo $SHLVL
[tiger@xx_239 ~]$ export SHLVL=1001
[tiger@xx_239 ~]$ echo $SHLVL
1001
[tiger@xx_239 ~]$ bash
bash: warning: shell level (1002) too high, resetting to 1
[tiger@xx_239 ~]$ echo $SHLVL
1
突破1001
哈,还是这个快。
牛人一个
靠,太猛鸟。
不过这里的1001应该不是第一层吧
如果1000以后不是真正的第一层……这么说来Inception里男主回到现实以后的现实仍然不是真正的现实??!
晕晕了
有意思!
盗梦终端:如何进入第1000层梦境
#!/bin/bash
#this will go to lvl 1000 dream!
if test $SHLVL -lt 999; then
echo level $((SHLVL+1))
bash -f $0
fi
echo level $((SHLVL+1))
bash
保存为 bash1000,直接运行即可 进入1000层梦境