shlex– 简单的词法分析

源代码: Lib / shlex.py


shlex类可以很容易地编写类似于语法分析器的词法分析器Unix shell。这对于编写小语言(例如,在Pythonapplications的运行控制文件中)或解析引用的字符串通常很有用.

shlex模块定义了以下函数:

shlex.splits, comments=False, posix=True

使用类似shell的语法拆分字符串s。如果commentsFalse(默认值),将禁用给定字符串中的注释解析(将commenters实例shlex属性设置为空字符串)。此函数默认在POSIX模式下运行,但如果posix参数为false,则使用非POSIX模式.

注意

split()函数实例shlex实例,传递None s将读取字符串从标准输入分开.

shlex.quote (s )

返回一个shell转义版本的字符串s。返回值是一个字符串,可以安全地用作shell命令行中的一个标记,用于不能使用列表的情况.

这个成语是不安全的:

>>> filename = "somefile; rm -rf ~">>> command = "ls -l {}".format(filename)>>> print(command)  # executed by a shell: boom!ls -l somefile; rm -rf ~

quote()让你插上安全漏洞:

>>> from shlex import quote>>> command = "ls -l {}".format(quote(filename))>>> print(command)ls -l "somefile; rm -rf ~">>> remote_command = "ssh home {}".format(quote(command))>>> print(remote_command)ssh home "ls -l """""somefile; rm -rf ~""""""

引用与UNIX shellsplit()

>>> from shlex import split>>> remote_command = split(remote_command)>>> remote_command["ssh", "home", "ls -l "somefile; rm -rf ~""]>>> command = split(remote_command[-1])>>> command["ls", "-l", "somefile; rm -rf ~"]

3.3版本中的新功能

shlexmodule定义了以下类:

class shlex.shlexinstream=None, infile=None, posix=False, punctuation_chars=False

一个 shlex实例或子类实例是一个词法分析器对象。初始化参数(如果存在)指定从哪里读取字符。它必须是一个类似文件/流的对象read()readline()方法,ora字符串。如果没有给出参数,则输入将取自sys.stdin。第二个可选参数是文件名字符串,它设置infile属性的初始值。如果instream参数被省略或等于sys.stdin,这第二个参数默认为“stdin”。posix参数定义了操作模式:当posix不为真时(默认),shlex实例将以兼容模式运行。在POSIX模式下运行时,shlex将尽可能接近POSIX shellparsing规则。punctuation_chars参数提供了一种方法,使行为更接近真实的shell解析。这可以采用多个值:默认值False,保留在Python 3.5及更早版本中看到的行为。如果设置为True,则会更改字符();<>|&的解析:这些字符的任何运行(被认为是标点符号)都将作为单个标记返回。如果设置为非空字符串,则这些字符将用作标点字符。wordchars中出现的punctuation_chars属性中的任何字符都将从wordchars中删除。请参阅改进与壳的兼容性了解更多信息.

更改版本3.6:添加了punctuation_chars参数.

另见

模块configparser
用于配置文件的解析器类似于Windows .ini files.

shlex对象

一个 shlexinstance有以下方法:

shlex.get_token

返回一个令牌。如果使用push_token()堆叠令牌,则从堆栈弹出。否则,从输入流中读取一个。如果readingencounters立即结束文件,则返回eof(在非POSIX模式下为emptystring(""),在POSIX模式下为None)。

shlex.push_tokenstr

将参数推到令牌堆栈上

shlex.read_token// ()

读一个原始令牌。忽略回推堆栈,不要解释源请求。(这通常不是一个有用的切入点,为了完整起见,这里仅记录。)

shlex.sourcehookfilename

shlex检测到source请求(参见下面的source)此方法被赋予以下标记作为参数,并且期望返回由文件名和类似打开文件的对象组成的元组.

通常,此方法首先从参数中删除任何引号。如果结果是绝对路径名,或者没有有效的先前源请求,或者前一个源是流(例如sys.stdin),则结果为leftalone。否则,如果结果是相对路径名,则在源包含堆栈之前的文件名称的目录部分被预先添加(此行为类似于C预处理器处理的方式#include"file.h").

操作的结果被视为文件名,并作为元组的第一个组件返回,并在其上调用open()以产生第二个组件。(注意:这与instanceinitialization中的参数顺序相反!)

此钩子被公开,以便您可以使用它来实现目录搜索路径,添加文件扩展名和其他命名空间黑客。有一个nocorresponding’close’钩子,但是一个shlex实例会在它返回的时候调用源输入流的close()方法.

要更明确地控制源堆叠,请使用push_source()pop_source()方法

shlex.push_source// (newstream, newfile=None)

将输入源流推入输入堆栈。如果指定了filename参数,则稍后可以在错误消息中使用它。这是sourcehook()method.

shlex.pop_source()

从输入堆栈中取出最后推送的输入源。当词法分析器在堆叠输入流上达到EOF时,这与内部相同.

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

此方法以Unix C compilererror标签的格式生成错误消息leader;格式为""%s", line %d: ",其中%s替换为当前源文件的名称和%d使用当前输入行号(可选参数可以用来覆盖这些).

这个方便是为了鼓励shlex用户以Emacs和其他Unixtools所理解的标准,可解析格式生成错误消息.

的实例shlex子类有一些公共实例变量,它们可以控制词法分析,也可以用于调试:

shlex.commenters

被识别为注释初学者的字符串。从注释初学者到行尾的所有字符都将被忽略。仅包含"#"默认情况下

shlex.wordchars

将累积为多字符标记的字符串。Bydefault,包括所有ASCII字母数字和下划线。在POSIX模式下,还包括Latin-1集中的有色字符。如果punctuation_chars不为空,则可以在文件名规范和命令行参数中出现的字符~-./*?=也将包含在此属性中,并且punctuation_chars中出现的任何字符都将如果它们存在,则从wordchars中移除.

shlex.whitespace

将被视为空格并被跳过的字符。空白边界。默认情况下,包括空格,制表符,换行符和回车符.

shlex.escape

将被视为逃脱的角色。这只会在POSIXmode中使用,默认只包含"\"

shlex.quotes

将被视为字符串引号的字符。令牌累积,直到再次遇到相同的引号(因此,不同的引用类型在shell中保护彼此。)默认情况下,包括ASCII单引号和双引号.

shlex.escapedquotes

quotes中的字符将解释在escape中定义的转义字符。这仅用于POSIX模式,仅包含""" bydefault.

shlex.whitespace_split

如果True,标记只会以空格分割。例如,这对于使用shlex解析命令行很有用,gettokens与shell参数类似。如果此属性为True,punctuation_chars将无效,并且分割将仅在空格上发生。当使用punctuation_chars时,它可以提供更接近shell实现的解析,建议将whitespace_split保留为False(默认值).

shlex.infile

当前输入文件的名称,最初在类实例化时间设置或由以后的源请求堆叠。在构造错误消息时检查这个可能是有用的.

shlex.instream

这个shlex实例是读取字符的输入流

shlex.source

这个属性是None默认。如果为其指定了一个字符串,那么该字符串将被识别为类似于各种shell中的source关键字的词法级包含请求。也就是说,紧接着的标记将作为文件名打开,输入将从该流中取出直到EOF,此时该流的close()方法将被置换,输入源将再次成为原始输入流。Sourcerequests可以堆叠任意数量的级别

shlex.debug

如果这个属性是数字和1或更多,shlex实例将打印其行为的详细进度输出。如果您需要使用它,您可以阅读模块源代码以了解详细信息.

shlex.lineno

源行号(到目前为止看到的换行数加一).

shlex.token

令牌缓冲区。捕捉异常时检查这个可能是有用的.

shlex.eof

令牌用于确定文件结尾。这将被设置为空字符串(""),在非POSIX模式下,和None在POSIX模式下

shlex.punctuation_chars

将被视为标点符号的字符。标点符号的运行将作为单个标记返回。但请注意,将执行语义有效性检查:例如,’&gt;&gt;&gt;’可以作为令牌返回,即使它可能无法被shell识别出来.

版本3.6.

解析规则

在非POSIX模式下操作时,shlex将尽力遵守以下规则.

  • 单词中不能识别引号字符(Do"Not"Separate单词Do"Not"Separate);
  • 不识别转义字符;
  • 用引号括起字符保留引号中所有字符的字面值;
  • 关闭引号分开的单词("Do"Separate被解析为"Do"Separate);
  • 如果whitespace_splitFalse,任何字符都没有被称为单词字符,空格,或者报价将作为单字符令牌返回。如果它是True, shlex只会在空格中分离单词;
  • EOF用空字符串发出信号("");
  • 无法解析空字符串,即使引用了

在POSIX模式下操作时,shlex会尝试服从以下解析规则.

  • 报价被删除,不要分开单词("Do"Not"Separate"作为单个单词DoNotSeparate);
  • 非引用的转义字符(例如"\")保留后面的下一个字符的文字值;
  • 用引号中的字符括起来escapedquotes(例如""")保留引号内所有字符的字面值;
  • 用引号括起来的字符escapedquotes的一部分(例如""")保留引号内所有字符的字面值,但escape。转义字符只有在使用的引号或者自变量字符本身后才会保留其特殊含义。否则转义字符将被视为正常字符.
  • EOF用None值发出信号;
  • 引用空字符串("")是允许的.

改进了与Shell的兼容性

版本3.6中的新功能

// shlex类提供与常见的Unix shell(如bash, dash)执行的解析的兼容性,和sh。要利用此兼容性,请在构造函数中指定punctuation_chars参数。默认为False,保留了3.6之前的行为。但是,如果设置为True,则解析字符();<>|&已更改:这些字符的任何运行都作为单个标记返回。虽然没有shell的完整解析器(考虑到那里的多种shell,它将超出标准库的范围),但它确实允许您比其他方式更容易地执行命令行的处理。为了说明,您可以看到以下代码段的不同之处:

 >>> import shlex >>> text = "a && b; c && d || e; f >"abc"; (def \"ghi\")" >>> list(shlex.shlex(text)) ["a", "&", "&", "b", ";", "c", "&", "&", "d", "|", "|", "e", ";", "f", ">", ""abc"", ";", "(", "def", ""ghi"", ")"] >>> list(shlex.shlex(text, punctuation_chars=True)) ["a", "&&", "b", ";", "c", "&&", "d", "||", "e", ";", "f", ">", ""abc"", ";", "(", "def", ""ghi"", ")"]

当然,将返回对shell无效的令牌,并且你需要对返回的令牌执行自己的错误检查.

而不是通过True作为punctuation_chars参数的值,您可以传递具有特定字符的字符串,该字符串将用于确定哪些字符构成标点符号。例如:

>>> import shlex>>> s = shlex.shlex("a && b || c", punctuation_chars="|")>>> list(s)["a", "&", "&", "b", "||", "c"]

注意

当指定punctuation_chars时,wordchars属性用字符~-./*?=扩充。那是因为这些字符可以出现在文件名(包括通配符)和命令行代码中(例如--color=auto)。因此:

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

为了达到最佳效果,punctuation_chars应与posix=True。(注意 posix=Falseshlex。)

评论被关闭。