繁体   English   中英

bash如何解析ANSI-C引用字符串中的控制字符转义码?

[英]How does bash parse control character escape codes in ANSI-C quoted strings?

我在 JavaScript 中重新实现了 bash 的ANSI-C 引用字符串,但我无法理解如何解析其中的控制字符。 我看到lib/sh/strtrans.c中的代码是这样做的:

            case 'c':
              if (sawc)
                {
                  *sawc = 1;
                  *r = '\0';
                  if (rlen)
                    *rlen = r - ret;
                  return ret;
                }
              else if ((flags & 1) == 0 && *s == 0)
                ;               /* pass \c through */
              else if ((flags & 1) == 0 && (c = *s))
                {
                  s++;
                  if ((flags & 2) && c == '\\' && c == *s)
                    s++;        /* Posix requires $'\c\\' do backslash escaping */
                  c = TOCTRL(c);
                  break;
                }

并且TOCTRLinclude/chartypes.h中定义为

#  define TOCTRL(x) ((x) == '?' ? 0x7f : (TOUPPER(x) & 0x1f))

其中TOUPPER实际上是 C 的toupper function。

所以我期望的是它在“ \c ”之后的字符的第一个字节,如果它是一个字母,则将其大写,并且结果的前三位为零。

使用 NodeJS 脚本对此进行了详尽的测试,我发现此规则不适用于两种情况:

$ bash -c $'echo -n "\x01" | xxd -b'
00000000: 00000001                                               .
$ bash -c $'echo -n $\'\\c\x01\' | xxd -b'
00000000: 00000001 00000001                                      ..

$ bash -c $'echo -n "\x7F" | xxd -b'
00000000: 01111111                                               .
$ bash -c $'echo -n $\'\\c\x7F\' | xxd -b'
00000000: 00000001 01111111                                      ..

(抱歉,如果这令人困惑,我正在使用 ANSI-C 引用字符串生成 bash 命令,其中包含另一个 ANSI-C 引用字符串,以便我可以在\c之后插入任意字符)

如果将前 3 位清零会产生00000000字符(例如\c ( 00100000 ) 或\c@ ( 01000000 )),那就是 NULL,它会终止字符串并导致xxd不打印任何内容,但这并不奇怪。

我想知道为什么会这样。

我们还需要syntax.h

#define CTLESC '\001'
#define CTLNUL '\177'

strtrans.c下面有:

    case 'c':
      if (sawc)
    {
      *sawc = 1;
      *r = '\0';
      if (rlen)
        *rlen = r - ret;
      return ret;
    }
      else if ((flags & 1) == 0 && *s == 0)
    ;       /* pass \c through */
      else if ((flags & 1) == 0 && (c = *s))
    {
      s++;
      if ((flags & 2) && c == '\\' && c == *s)
        s++;    /* Posix requires $'\c\\' do backslash escaping */
      c = TOCTRL(c);
      break;
    }
    /*FALLTHROUGH*/
    default:
    if ((flags & 4) == 0)
      *r++ = '\\';
    break;
    }
  # c is 0x01 or 0x1f
  if ((flags & 2) && (c == CTLESC || c == CTLNUL))
    *r++ = CTLESC;     # adds 0x01
  *r++ = c;            # adds 0x01 or 0x1f
}

我不知道\c转义序列是从哪里来的。 不在 C 中,据我所知,我没有看到它使用过。 它从何而来? 我想说使用\c$'\x01'\c$'\x1f'将被视为“未定义的行为”,但我不知道实际上允许哪些字符。

我更喜欢xxd -p而不是xxd -b :p

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM