shell: bash中的冒号

shell scott 292℃ 0评论

前段时间有人在群上发了一个shell命令,问谁敢运行,还说最好在虚拟里运行.于是我研究了一下.

前言

先来shell命令吧.

  1. 1
    :(){ :|:& };:

2015.4.21 更新

感谢 nnkken 言简意明的告诉我真正的原因在于无限递归fork子进程。

而这几天我刚好在看 《UNIX环境高级编程》的第九章, 正好第9小节讲的有shell执行程序的原理,于是可以有理有据的更新一下了。

当然,可能写的还有很多不足或错误之处,可以留言告诉我,然后我完善一下。

shell中的冒号

看到这个shell代码,我第一个想法是难道是冒号的特殊用法?

于是查询了一下冒号的用法.

变量默认值

当变量VAR没有声明或者为NULL时,将VAR设置为默认值DEFAULT。

  1. 1
    ${VAR:=DEFAULT}

例如下面的测试代码

  1. 1
    tiankonguse@tiankonguse:~$ base="hello>"
  2.  
  3. 1
    tiankonguse@tiankonguse:~$ echo ${first:="word>"}
  4. 1
    word
  5. 1
    tiankonguse@tiankonguse:~$ echo $first
  6. 1
    word
  7.  
  8. 1
    tiankonguse@tiankonguse:~$ second="tiankonguse>"
  9. 1
    tiankonguse@tiankonguse:~$ echo $second
  10. 1
    tiankonguse
  11.  
  12. 1
    tiankonguse@tiankonguse:~$ echo ${second:="word>"}
  13. 1
    tiankonguse

空语句

学过 python 的人都知道 python 中有 pass 这个语法.

bash 中的冒号也有这个作用.

  1. 1
    if [ $today == "2011-08-29>" ]; then
  2. 1
    :
  3. 1
    else
  4. 1
    echo $today;
  5. 1
    fi

清空文件

  1. 1
    : > test

shell 函数

看了那几个冒号的作用, 发现那段代码都不符合.

  1. 1
    :(){ :|:& };:

然后自己冷静下来分析一下, 发现这不就是一个函数的递归定义然后调用吗?

分析

1
:(){ :|:& }

是函数定义.

1
:

是函数调用.

多条 bash 语句写在同一行时,就需要使逗号分隔了.

在函数定义中,

1
:|:&

是函数体.

然后

1
:|:&

又可以看做 调用函数

1
:

后把输出作为函数

1
:

的输入,并后台运行.

这样的话相当于程序死循环和无限递归了,自然系统就会有问题了.

~~ 我们还可以简写为

1
:(){ :; };:

吧. ~~

上面我说死循环和无限递归的时候, 并没有意识到这样做对机器有什么影响。

死循环和无限递归就像下面的例子,对系统影响不大的。

  1. 1
    while(1){
  2. 1
    ;
  3. 1
    }
  4.  
  5. 1
    void dfs(){
  6. 1
    dfs();
  7. 1
    }

为什么影响不大呢?如果是这样的话, 程序一直在运行,但是只消耗CPU资源而已。

但是我们使用管道后就不一样了。

比如这本书 《UNIX环境高级编程》上面的这个图

shell: bash中的冒号

shell: bash中的冒号

我这边测试时这个样子

  1. 1
    tiankonguse:bin $ ps -f | ./cat1 | ./cat2 &
  2. 1
    [1] 26964
  3.  
  4. 1
    tiankonguse:bin $
  5. 1
    UID PID PPID C STIME TTY TIME CMD
  6. 1
    tiankonguse 15822 15821 0 09:12 pts/0 00:00:00 -bash
  7. 1
    tiankonguse 26962 15822 0 09:34 pts/0 00:00:00 ps -f
  8. 1
    tiankonguse 26963 15822 0 09:34 pts/0 00:00:00 ./cat1
  9. 1
    tiankonguse 26964 15822 0 09:34 pts/0 00:00:00 ./cat2
  10.  
  11. 1
    [1]+ Done ps -f | ./cat1 | ./cat2

我们使用管道时,它会fork子进程。

开启子进程会消耗FD的。

然后结果就像 nnkken 说的那样,结果是下面的样子。

  1. 1
    while(1) {
  2. 1
    fork();
  3. 1
    }

系统死了的原因是FD使用完了。

bash 内的特殊字符

之前我曾总结过, bash 内特殊字符有这些. 特殊字符和引用

当然, 那个文档是去年4月份整理的,那时候才学疏浅的我不知道有没有总结错误.

我们就假设没错把, 那样的话, 里面没有看到冒号,所以我们可以使用冒号当做函数名字了.

测试

  1. 1
    tiankonguse@tiankonguse:~$ :(){ echo "tiankonguse $FUNCNAME>"; };:;
  2. 1
    tiankonguse :

类似的字符还有很多, 比如

  1. 1
    tiankonguse@tiankonguse:~$ .(){ echo "tiankonguse $FUNCNAME>"; };.;
  2. 1
    tiankonguse .

参考资料

原文:http://www.kuqin.com/shuoit/20150424/345862.html

转载请注明:osetc.com » shell: bash中的冒号

喜欢 (0)or分享 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址