Bash 反斜杠在反斜杠中到底是如何工作的?
从: 反勾号内的反斜杠(\)以不明显的方式处理:Bash 反斜杠在反斜杠中到底是如何工作的?,bash,escaping,backslash,backticks,Bash,Escaping,Backslash,Backticks,从: 反勾号内的反斜杠(\)以不明显的方式处理: $ echo "`echo \\a`" "$(echo \\a)" a \a $ echo "`echo \\\\a`" "$(echo \\\\a)" \a \\a 但是FAQ并没有分解导致这种差异的解析规则。我找到的manbash中唯一相关的引用是: 当使用旧式的反引号替换形式时,反斜杠保留其字面含义,后面跟$、`、或除外 “$(echo\\a)”和“$
$ echo "`echo \\a`" "$(echo \\a)"
a \a
$ echo "`echo \\\\a`" "$(echo \\\\a)"
\a \\a
但是FAQ并没有分解导致这种差异的解析规则。我找到的manbash
中唯一相关的引用是:
当使用旧式的反引号替换形式时,反斜杠保留其字面含义,后面跟$、`、或除外
“$(echo\\a)”
和“$(echo\\\\a)”
的大小写非常简单:反斜杠,即转义字符,正在将自身转义为文字反冲。因此,\\
的每个实例在输出中都成为\
。但我很难理解backtick案例的类似逻辑。基本规则是什么?观察到的输出是如何遵循的
最后,一个相关的问题。。。如果不引用反勾号,则会出现“不匹配”错误:
这个案子发生了什么
更新
Re:我的主要问题是,我有一套解释所有行为的规则的理论,但仍然看不出它是如何从bash中任何记录的规则中得出的。以下是我提议的规则
在反斜杠内部,字符前面的反斜杠只返回该字符。也就是说,一个反斜杠没有效果。这适用于所有角色,除了反冲本身和反勾号。对于反斜杠本身,\\
将成为转义反斜杠。它将逃避它的下一个角色
让我们通过一个例子来了解这一点:
a=xx
echo "`echo $a`" # prints the value of $a
echo "`echo \$a`" # single backslash has no effect: equivalent to above
echo "`echo \\$a`" # escaping backslash make $ literal
印刷品:
xx
xx
$a
让我们从这个角度分析原始示例:
echo "`echo \\a`"
在这里,\
产生一个转义反斜杠,但是当我们“转义”a
时,我们只返回a
,所以它打印a
echo "`echo \\\\a`"
这里,第一对
\\
产生一个转义反斜杠,该反斜杠应用于\
,产生一个文字反斜杠。也就是说,前3个\\\
在输出中成为单个文本\
。剩下的\a
只产生a
。最后的结果是,\a
做了更多的研究,以找到所发生事情的参考和规律。来自it州
当使用旧式的反引号替换形式时,反斜杠
保留其字面含义,后跟“$”、“`”或“\”时除外。
第一个不带反斜杠的反引号终止命令
替代。使用$(命令)窗体时,所有字符
括号组成命令;没有人受到特殊对待
换句话说,\、\$和'inside of``在命令替换之前由CLI解析器处理。其他所有内容都传递给命令替换进行处理
让我们一步一步地看问题中的每个例子。在#之后,我介绍了在执行``或$()之前CLI解析器如何处理命令替换
你的第一个例子解释了
$ echo "`echo \\a`" # echo \a
a
$ echo "$(echo \\a)" # echo \\a
\a
你的第二个例子解释了:
$ echo "`echo \\\\a`" # echo \\a
\a
$ echo "$(echo \\\\a)" # echo \\\\a
\\a
你的第三个例子:
a=xx
$ echo "`echo $a`" # echo xx
xx
$ echo "`echo \$a`" # echo $a
xx
echo "`echo \\$a`" # echo \$a
$a
您使用$()的第三个示例
这样的逻辑很简单。所以我们看一下bash源代码(4.4)本身 subst.c:9273
case'`://*反引号命令替换*/
{
t_指数=sindex++;
temp=string\u extract(string,&sindex,“`”,SX\u REQMATCH);
/*根据t_索引测试sindex是为了允许
`通过,以便向后兼容*/
if(temp==&extract_string_error | | temp==&extract_string_fatal)
{
if(sindex-1==t_索引)
{
sindex=t_指数;
转到添加_字符;
}
最后一个命令退出值=执行失败;
报告_错误(u(“错误替换:在%s中没有结束“`”),字符串+t_索引);
自由(弦);
免费(istring);
返回((temp==&提取字符串错误)?&展开单词错误
:&展开\u word\u fatal);
}
如果(某物)
*扩展的某物=1;
如果(word->flags&W_NOCOMSUB)
/*sindex+1,因为字符串[sindex]='`'*/
temp1=子字符串(字符串,t_索引,sindex+1);
其他的
{
反斜杠(温度);
tword=命令替换(临时,引用);
temp1=tword?tword->word:(char*)空;
如果(第二)
处理单词描述(第二个);
}
免费(临时);
temp=temp1;
转到美元添加字符串;
}
如您所见,调用函数de_反斜杠(temp)在c中更新字符串的字符串上的代码>。相同功能的代码如下所示
subst.c:1607
/* Remove backslashes which are quoting backquotes from STRING. Modifies
STRING, and returns a pointer to it. */
char *
de_backslash(string) char *string;
{
register size_t slen;
register int i, j, prev_i;
DECLARE_MBSTATE;
slen = strlen(string);
i = j = 0;
/* Loop copying string[i] to string[j], i >= j. */
while (i < slen)
{
if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
string[i + 1] == '$'))
i++;
prev_i = i;
ADVANCE_CHAR(string, slen, i);
if (j < prev_i)
do
string[j++] = string[prev_i++];
while (prev_i < i);
else
j = i;
}
string[j] = '\0';
return (string);
}
同样的输出是\\$a
。现在让我们在bash中测试同样的功能
$a=xxx
$echo“$(echo\\$a)”
\xxx
$echo“`echo\\\\$a`”
\xxx
无法在bash 5.0.7上重现该错误,您有哪个版本?@oguzismailGNU bash,5.0.2(1)版-发行版(x86\u 64-apple-darwin16.7.0)
该“不匹配”错误看起来像设置了failglob
,出于某种原因,bash试图将\a
视为文件名模式。我不知道它为什么会这样做;echo$(@KamilCuk)这是最近引入的一个bug。我不得不说,这相当令人失望,但我想,在如此复杂的软件工具下,它会发生。如果有这样的事情,可能值得向bash bug追踪器报告。
$ echo "$(echo $a)" # echo $a
xx
$ echo "$(echo \$a)" # echo \$a
$a
$ echo "$(echo \\$a)" # echo \\$a
\xx
/* Remove backslashes which are quoting backquotes from STRING. Modifies
STRING, and returns a pointer to it. */
char *
de_backslash(string) char *string;
{
register size_t slen;
register int i, j, prev_i;
DECLARE_MBSTATE;
slen = strlen(string);
i = j = 0;
/* Loop copying string[i] to string[j], i >= j. */
while (i < slen)
{
if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
string[i + 1] == '$'))
i++;
prev_i = i;
ADVANCE_CHAR(string, slen, i);
if (j < prev_i)
do
string[j++] = string[prev_i++];
while (prev_i < i);
else
j = i;
}
string[j] = '\0';
return (string);
}