• Bash 中 SHLVL 变量为 1000 的时候


    SHLVL 环境变量代表 Shell 嵌套执行的深度。

    $ echo $SHLVL

    1

    $ bash

    $ echo $SHLVL

    2

    $ bash

    $ echo $SHLVL

    3

    在 Bash 里,这个值的范围是 [0, 1000],0 是怎么来的呢?是在上次的 SHLVL 值为负数的时候:

    $ SHLVL=-1

    $ bash

    $ echo $SHLVL

    0

    当 SHLVL 的值超过 1000 时,会自动重置到 1。

    $ SHLVL=1000

    $ bash

    bash: warning: shell level (1001) too high, resetting to 1

    $ echo $SHLVL

    1

    我也本以为就是这样了,然而却发现个特例:

    $ SHLVL=999

    $ bash

    $ echo $SHLVL

    在嵌套 1000 层的时候,SHEVL 看起来是个空字符串,但在 Shell 里很多东西眼见都不为实,所以我们用 16 进制看看:

    $ SHLVL=999 bash -c 'echo -n "$SHLVL" | hexdump'

    0b 01

    $ SHLVL=999 bash -c 'echo -n "$SHLVL" | hexdump'

    0f 01

    $ SHLVL=999 bash -c 'echo -n "$SHLVL" | hexdump'

    04 01 

    这个值原来是个随机字符串,在我的 Mac 上是两个控制字符(不可见字符),所以看起来像是空字符串。而在另外一台 Red Hat 上执行了下是一些肉眼可见的乱码:

    $ SHLVL=999 bash -c 'echo "$SHLVL"'

    �[g�

    总之,也就是说 SHEVL 实际的值会在 [0, 999] 以及这个不确定的值这 1001 个值里轮询,不会真正到达 1000。

    看了下 Bash 源码:

    void
    adjust_shell_level (change)
         int change;
    {
      char new_level[5], *old_SHLVL;
      intmax_t old_level;
      SHELL_VAR *temp_var;
    
      old_SHLVL = get_string_value ("SHLVL");
      if (old_SHLVL == 0 || *old_SHLVL == '' || legal_number (old_SHLVL, &old_level) == 0)
        old_level = 0;
    
      shell_level = old_level + change;
      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;
        }
    
      /* We don't need the full generality of itos here. */
      if (shell_level < 10)
        {
          new_level[0] = shell_level + '0';
          new_level[1] = '';
        }
      else if (shell_level < 100)
        {
          new_level[0] = (shell_level / 10) + '0';
          new_level[1] = (shell_level % 10) + '0';
          new_level[2] = '';
        }
      else if (shell_level < 1000)
        {
          new_level[0] = (shell_level / 100) + '0';
          old_level = shell_level % 100;
          new_level[1] = (old_level / 10) + '0';
          new_level[2] = (old_level % 10) + '0';
          new_level[3] = '';
        }
    
      temp_var = bind_variable ("SHLVL", new_level, 0);
      set_auto_export (temp_var);
    }
    
    static void
    initialize_shell_level ()
    {
      adjust_shell_level (1);
    }

    它把数字转字符串的逻辑只写到 shell_level < 1000 的地方,漏掉了最后一个 else 的样子,导致 SHLVL 的值成为了一个未初始化的字符串。我在 bug-bash 上发了邮件,这个 bug 会在 Bash 4.4 中修复 http://lists.gnu.org/archive/html/bug-bash/2015-09/msg00057.html。顺便说一句,ksh 和 zsh 都没有这个 1000 限制。

  • 相关阅读:
    Mina入门demo
    MySQL数据库插入中文时出现Incorrect string value: 'xE6x97xB7xE5x85xA8' for column 'sz_name' at row 1
    synchronized和volatile
    springboot+Zookeeper+Dubbo入门
    zookeeper的安装
    windows下dubbo-admin的安装
    Java 枚举类
    Mysql 解压版 安装时候的注意事项
    Java——JDBC鶸笔记
    《初识Java微信公众号开发》 学习中遇到的困难
  • 原文地址:https://www.cnblogs.com/ziyunfei/p/4802826.html
Copyright © 2020-2023  润新知