在进程argv中意外的字符串转义

时间:2015-10-08 07:27:50

标签: bash shell argv

有点惊讶:

$ node -p 'process.argv' $SHELL '$SHELL' \t '\t' '\\t'
[ 'node', '/bin/bash', '$SHELL', 't', '\\t', '\\\\t' ]

$ python -c 'import sys; print sys.argv' $SHELL '$SHELL' \t '\t' '\\t'
['-c', '/bin/bash', '$SHELL', 't', '\\t', '\\\\t']

预期与以下行为相同:

$ echo $SHELL '$SHELL' \t '\t' '\\t'
/bin/bash $SHELL t \t \\t

我需要传递的内容是什么。

为什么在进程argv中使用'\t''\\t'进行额外转义?为什么处理方式与'$SHELL'不同?这实际上来自哪里?为什么与echo行为不同?

首先我认为这是minimist部分的一些 extras ,但是对于裸Node.js和Python都是如此。可能会遗漏一些明显的东西。

2 个答案:

答案 0 :(得分:3)

使用$'...'表单在BASH中传递\t\n\r\0等转义序列:

python -c 'import sys; print sys.argv' $SHELL '$SHELL' \t $'\t' $'\\t'
['-c', '/bin/bash', '$SHELL', 't', '\t', '\\t']

根据man bash

  

$'string'形式的单词是专门处理的。单词扩展为字符串,替换为ANSI C标准指定的反斜杠转义字符。反斜杠转义序列(如果存在)按如下方式解码:

\a     alert (bell)
\b     backspace
\e
\E     an escape character
\f     form feed
\n     new line
\r     carriage return
\t     horizontal tab
\v     vertical tab
\\     backslash
\'     single quote
\"     double quote
\nnn   the eight-bit character whose value is the octal value nnn (one to three digits)
\xHH   the eight-bit character whose value is the hexadecimal value HH (one or two hex digits)
\uHHHH the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value HHHH (one to four hex digits)
\UHHHHHHHH the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value HHHHHHHH  (one  to  eight  hex digits)
\cx    a control-x character

答案 1 :(得分:1)

在python和node.js中,print与标量字符串一起使用的方式与它与集合一起使用的方式之间存在差异。

字符串只是作为一系列字符打印。结果输出通常是用户期望看到的,但它不能用作语言中字符串的表示。但是当打印出列表/数组时,你得到的是一个有效的列表/数组文字,可以在程序中使用。

例如,在python中:

>>> print("x")
x
>>> print(["x"])
['x']

打印字符串时,您只看到字符。但是当打印包含字符串的列表时,python会添加引号字符,因此输出是有效的列表文字。同样,如果需要,它会添加反斜杠:

>>> print("\\")
\
>>> print(["\\"])
['\\']

node.js以完全相同的方式工作:

$ node -p '"\\"'
\
$ node -p '["\\"]'
[ '\\' ]

当您打印包含单个反斜杠的字符串时,您只需获得一个反斜杠。但是当您打印包含由单个反斜杠组成的字符串的列表/数组时,您会得到一个带引号的字符串,其中反斜杠使用反斜杠进行转义,允许它在程序中用作文字。

与在node和python中打印字符串一样,标准echo shell实用程序只打印字符串中的实际字符。在标准shell中,没有类似于节点和python打印数组的机制。但是,Bash确实提供了一种机制,用于以可以用作bash程序一部分的格式打印变量的值:

$ quote=\"
# $quote is a single character:
$ echo "${#quote}"
1
# $quote prints out as a single quote, as you would expect
$ echo "$quote"
"
# If you needed a representation, use the 'declare' builtin:
$ declare -p quote
declare -- quote="\""
# You can also use the "%q" printf format (a bash extension)
$ printf "%q\n" "$quote"
\"

(参考文献:declareprintf上的bash手册。或者在bash会话中输入help declarehelp printf。)

但是,这不是完整的故事。了解shell如何解释您键入的内容也很重要。换句话说,当你写

some_utility  \" "\"" '\"'

some_utility在argv数组中实际看到了什么?

在标准shell(包括bash)的大多数上下文中,像\t这样的C风格转义序列不会被解释为这样。 (标准shell实用程序printf在格式字符串中出现时会解释这些序列,而其他一些标准实用程序也会解释序列,但shell本身不会解释。)标准shell对反斜杠的处理依赖于背景:

  • 不带引号的字符串:反斜杠引用以下字符,无论它是什么(除非它是换行符,在这种情况下,反斜杠和换行符都从输入中删除)。

  • 双引号字符串:反斜杠可用于转义字符 $ \ &#34; ,< KBD>`;此外,从输入中删除后跟换行符的反斜杠,如未加引号的字符串。在bash中,如果启用了历史记录扩展(默认情况下在交互式 shell中),则也可以使用反斜杠来避免的历史记录扩展,但会保留反斜杠在最后的字符串中。

  • 单引号字符串:反斜杠被视为普通字符。 (因此,无法在单引号字符串中包含单引号。)

Bash增加了两个引用机制:

  • C风格引用,$'...'。如果单引号字符串前面有美元符号,则字符串中的C样式转义序列的解释方式与C编译器的解释方式大致相同。这包括标准的空白字符,如换行符(\n),八进制,十六进制和unicode转义符(\010\x0a\u000A\U0000000A),以及一些非C序列,包括&#34;控制&#34;字符(\cJ)和ESC字符\e\E(与\x1b相同)。反斜杠也可用于转义 \ &#39; &#34; 。 (请注意,这是与双引号字符串中可反斜字符列表不同的列表;此处,美元符号或背景之前的反斜杠不是特殊,而单引号前的反斜杠是特殊;此外,不解释反斜杠换行序列。)

  • 特定于语言环境的翻译:{{1​​}}。如果双引号字符串前面有美元符号,则反斜杠(以及变量扩展和命令替换)将被解释为使用普通的双引号字符串,然后在由当前语言环境确定的消息目录中查找该字符串。

(参考文献:Posix standardBash manual。)