24.3. shlex —— 简单的词义分析


    类可用于编写类似 Unix shell 的简单词义分析程序。通常可用于编写“迷你语言”(如 Python 应用程序的运行控制文件)或解析带引号的字符串。

    shlex 模块中定义了以下函数:

    (s, comments=False, posix=True)

    用类似 shell 的语法拆分字符串 s。如果 comments 为 (默认值),则不会解析给定字符串中的注释 (commenters 属性的 实例设为空字符串)。 本函数默认工作于 POSIX 模式下,但若 posix 参数为 False,则采用非 POSIX 模式。

    注解

    Since the split() function instantiates a instance, passing None for s will read the string to split from standard input.

    shlex.quote(s)

    返回经过 shell 转义的字符串 s 。返回值为字符串,可以安全地作为 shell 命令行中的单词使用,可用于不能使用列表的场合。

    This idiom would be unsafe:

    quote() lets you plug the security hole:

    1. >>> command = 'ls -l {}'.format(quote(filename))
    2. >>> print(command)
    3. ls -l 'somefile; rm -rf ~'
    4. >>> remote_command = 'ssh home {}'.format(quote(command))
    5. >>> print(remote_command)
    6. ssh home 'ls -l '"'"'somefile; rm -rf ~'"'"''

    这种包装方式兼容于 UNIX shell 和 。

    3.3 新版功能.

    shlex 模块中定义了以下类:

    class shlex.shlex(instream=None, infile=None, posix=False, punctuation_chars=False)

    A instance or subclass instance is a lexical analyzer object. The initialization argument, if present, specifies where to read characters from. It must be a file-/stream-like object with read() and methods, or a string. If no argument is given, input will be taken from sys.stdin. The second optional argument is a filename string, which sets the initial value of the infile attribute. If the instream argument is omitted or equal to sys.stdin, this second argument defaults to “stdin”. The posix argument defines the operational mode: when posix is not true (default), the instance will operate in compatibility mode. When operating in POSIX mode, shlex will try to be as close as possible to the POSIX shell parsing rules. The punctuation_chars argument provides a way to make the behaviour even closer to how real shells parse. This can take a number of values: the default value, False, preserves the behaviour seen under Python 3.5 and earlier. If set to True, then parsing of the characters ();<>|& is changed: any run of these characters (considered punctuation characters) is returned as a single token. If set to a non-empty string of characters, those characters will be used as the punctuation characters. Any characters in the attribute that appear in punctuation_chars will be removed from wordchars. See for more information.

    在 3.6 版更改: 加入 punctuation_chars 参数。

    参见

    configparser 模块

    配置文件解析器,类似于 Windows 的 .ini 文件。

    实例具备以下方法:

    shlex.get_token()

    返回一个单词。如果所有单词已用 push_token() 堆叠在一起了,则从堆中弹出一个单词。否则就从输入流中读取一个。如果读取时遇到文件结束符,则会返回 eof`(在非 POSIX 模式下为空字符串 ` ’’,在 POSIX 模式下为 ``None)。

    shlex.push_token(str)

    将参数值压入单词堆栈。

    shlex.read_token()

    读取一个原单词。忽略堆栈,且不解释源请求。(通常没什么用,只是为了完整起见。)

    shlex.sourcehook(filename)

    当 检测到源请求(见下面的 source),本方法被赋予以下单词作为参数,并应返回一个由文件名和打开的文件对象组成的元组。

    通常本方法会先移除参数中的引号。如果结果为绝对路径名,或者之前没有有效的源请求,或者之前的源请求是一个流对象(比如 sys.stdin),那么结果将不做处理。否则,如果结果是相对路径名,那么前面将会加上目录部分,目录名来自于源堆栈中前一个文件名(类似于 C 预处理器对 #include "file.h" 的处理方式)。

    结果被视为一个文件名,并作为元组的第一部分返回,元组的第二部分以此为基础调用 获得。(注意:这与实例初始化中的参数顺序相反!)

    若要更明确地控制源堆栈,请采用 push_source() 和 方法。

    shlex.push_source(newstream, newfile=None)

    将输入源流压入输入堆栈。如果指定了文件名参数,以后错误信息中将会用到。这与 sourcehook() 内部使用的方法相同。

    shlex.pop_source()

    从输入堆栈中弹出最后一条输入源。当遇到输入流的 EOF 时,内部也使用同一方法。

    shlex.error_leader(infile=None, lineno=None)

    本方法生成一条错误信息的首部,以 Unix C 编译器错误标签的形式;格式为``’”%s”, line %d: ‘,其中 ``%s 被替换为当前源文件的名称,%d 被替换为当前输入行号(可用可选参数覆盖)。

    这是个快捷函数,旨在鼓励 用户以标准的、可解析的格式生成错误信息,以便 Emacs 和其他 Unix 工具理解。

    shlex 子类的实例有一些公共实例变量,这些变量可以控制词义分析,也可用于调试。

    shlex.commenters

    将被视为注释起始字符串。从注释起始字符串到行尾的所有字符都将被忽略。默认情况下只包括 '#'

    shlex.wordchars

    The string of characters that will accumulate into multi-character tokens. By default, includes all ASCII alphanumerics and underscore. In POSIX mode, the accented characters in the Latin-1 set are also included. If is not empty, the characters ~-./*?=, which can appear in filename specifications and command line parameters, will also be included in this attribute, and any characters which appear in will be removed from wordchars if they are present there.

    shlex.whitespace

    将被视为空白符并跳过的字符。空白符是单词的边界。默认包含空格、制表符、换行符和回车符。

    shlex.escape

    将视为转义字符。仅适用于 POSIX 模式,默认只包含 '\'

    shlex.quotes

    将视为引号的字符。单词中的字符将会累至再次遇到同样的引号(因此,不同的引号会像在 shell 中一样相互包含。)默认包含 ASCII 单引号和双引号。

    shlex.escapedquotes

    quotes 中的字符将会解析 定义的转义字符。这只在 POSIX 模式下使用,默认只包含 '"'

    shlex.whitespace_split

    If True, tokens will only be split in whitespaces. This is useful, for example, for parsing command lines with shlex, getting tokens in a similar way to shell arguments. If this attribute is True, will have no effect, and splitting will happen only on whitespaces. When using punctuation_chars, which is intended to provide parsing closer to that implemented by shells, it is advisable to leave whitespace_split as False (the default value).

    shlex.infile

    当前输入的文件名,可能是在类实例化时设置的,或者是由后来的源请求堆栈生成的。在构建错误信息时可能会用到本属性。

    shlex.instream

    实例正从中读取字符的输入流。

    shlex.source

    本属性默认值为 None。 如果给定一个字符串,则会识别为包含请求,类似于各种 shell 中的 source 关键字。 也就是说,紧随其后的单词将作为文件名打开,作为输入流,直至遇到 EOF 后调用流的 close() 方法,然后原输入流仍变回输入源。Source 请求可以在词义堆栈中嵌套任意深度。

    shlex.debug

    shlex.lineno

    源的行数(到目前为止读到的换行符数量加 1)。

    shlex.token

    单词缓冲区。在捕获异常时可能会用到。

    shlex.eof

    用于确定文件结束的单词。在非 POSIX 模式下,将设为空字符串 '',在 POSIX 模式下被设为 None

    shlex.punctuation_chars

    Characters that will be considered punctuation. Runs of punctuation characters will be returned as a single token. However, note that no semantic validity checking will be performed: for example, ‘>>>’ could be returned as a token, even though it may not be recognised as such by shells.

    3.6 新版功能.

    在非 POSIX 模式下时, 会试图遵守以下规则:

    • 不识别单词中的引号(Do"Not"Separate 解析为一个单词 Do"Not"Separate)。

    • 不识别转义字符;

    • 成对的引号会将单词分离("Do"Separate 解析为 "Do"Separate)。

    • 如果 whitespace_splitFalse,则未声明为单词字符、空白或引号的字符将作为单字符标记返回。若为 True, 则 只根据空白符拆分单词。

    • EOF 用空字符串()表示;

    • 空字符串无法解析,即便是加了引号。

    在 POSIX 模式时,shlex 将尝试遵守以下解析规则:

    • 引号会被剔除,且不会拆分单词( "Do"Not"Separate" 将解析为单个单词 DoNotSeparate)。

    • 未加引号包裹的转义字符(如 '\' )保留后一个字符的字面意思;

    • 引号中的字符不属于 (例如,"'"),则保留引号中所有字符的字面值。

    • 若引号包裹的字符属于 escapedquotes (例如 '"'),则保留引号中所有字符的字面意思,属于 中的字符除外。仅当后跟后半个引号或转义字符本身时,转义字符才保留其特殊含义。否则,转义字符将视作普通字符。

    • EOF 用 None 表示。

    • 允许出现引号包裹的空字符串('')。

    3.6 新版功能.

    类提供了与常见 Unix shell(如 bashdash 和``sh``)的解析兼容性。为了充分利用这种兼容性,请在构造函数中设定 punctuation_chars 参数。该参数默认为 False,维持 3.6 以下版本的行为。如果设为 True,则会改变对 ();<>|& 字符的解析方式:这些字符都将视为单个标记返回。虽然不算是完整的 shell 解析程序(考虑到 shell 的多样性,超出了标准库的范围),但确实能比其他方式更容易进行命令行的处理。以下代码段演示了两者的差异:

    1. >>> import shlex
    2. >>> list(shlex.shlex(text))
    3. ['a', '&', '&', 'b', ';', 'c', '&', '&', 'd', '|', '|', 'e', ';', 'f', '>',
    4. "'abc'", ';', '(', 'def', '"ghi"', ')']
    5. >>> list(shlex.shlex(text, punctuation_chars=True))
    6. ['a', '&&', 'b', ';', 'c', '&&', 'd', '||', 'e', ';', 'f', '>', "'abc'",
    7. ';', '(', 'def', '"ghi"', ')']

    当然,返回的词法单元对 shell 无效,需要对返回的词法单元自行进行错误检查。

    punctuation_chars 参数可以不传入 True ,而是传入包含特定字符的字符串,用于确定由哪些字符构成标点符号。例如:

    注解

    如果指定了 punctuation_chars,则 wordchars 属性的参数会是 ~-./*?=。因为这些字符可以出现在文件名(包括通配符)和命令行参数中(如 --color=auto)。因此:

    1. >>> import shlex
    2. >>> s = shlex.shlex('~/a && b-c --color=auto || d *.py?',
    3. ... punctuation_chars=True)
    4. >>> list(s)
    5. ['~/a', '&&', 'b-c', '--color=auto', '||', 'd', '*.py?']