[英]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;
}
并且TOCTRL
在include/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.