跳转到主要内容

通过正则表达式在文件中添加和删除行

项目描述

Project Status: Active — The project has reached a stable, usable state and is being actively developed. CI Status https://codecov.io/gh/jwodder/lineinfile/branch/master/graph/badge.svg https://img.shields.io/pypi/pyversions/lineinfile.svg MIT License

GitHub | PyPI | 问题 | 变更日志

受(但不隶属于)同名Ansible模块的启发,lineinfile提供了一种命令和库,可以在文件中不存在时添加一行,并从文件中删除与模式匹配的行。有选项可以使用正则表达式查找要更新的行或确定要插入前后的行。有选项可以在自定义文件扩展名下备份修改后的文件,并将不存在的文件视为空文件。甚至还有一个选项,可以根据匹配正则表达式中的捕获组来确定要插入的行。

与Ansible模块不同,此包不执行任何文件属性管理;这些必须在外部设置。

安装

lineinfile 需要Python 3.6或更高版本。只需使用Python 3的pip(您有pip吗?)来安装lineinfile及其依赖项

python3 -m pip install lineinfile

示例

一个粗略的.ini文件更新器:将theoption设置为value,如果在文件中找不到对theoption的设置,则在“[thesection]”行之后添加一个

$ lineinfile add \
    --after-first "^\[thesection\]$" \
    -e "^theoption\s*=" \
    "theoption = thevalue" \
    settings.ini

Python中的等效操作

from lineinfile import AfterFirst, add_line_to_file

add_line_to_file(
    "settings.ini",
    "theoption = thevalue",
    regexp=r"^theoption\s*=",
    inserter=AfterFirst(r"^\[thesection\]$"),
)

替换“foo = ...”的第一个实例为“foo = 'bar'”,保留缩进,并在即使没有进行更改的情况下创建具有扩展名.bak的文件备份

$ lineinfile add \
    -e "^(\s*)foo\s*=" \
    --backrefs \
    --match-first \
    --backup-always -i.bak \
    "\1foo = 'bar'" \
    file.py

Python中的等效操作

from lineinfile import ALWAYS, add_line_to_file

add_line_to_file(
    "file.py",
    r"\1foo = 'bar'",
    regexp=r"^(\s*)foo\s*=",
    backrefs=True,
    match_first=True,
    backup=ALWAYS,
    backup_ext=".bak",
)

命令行使用

lineinfile命令有两个子命令,addremove

add

lineinfile add [<options>] <line> [<file>]
lineinfile add [<options>] -L <line> [<file>]

如果文件中不存在指定的line(在展开反斜杠转义后),则将其添加到文件中。如果使用带有-e/--regexp选项的Python正则表达式,并且它匹配文件中的任何行,则line将替换最后一个匹配的行(如果提供了--match-first,则替换第一个匹配的行)。如果没有匹配正则表达式(或没有指定正则表达式)并且line在文件中找不到,则默认情况下在文件末尾插入行;这可以通过--after-first--after-last--before-first--before-last--bof选项进行更改。

如果命令行中没有给出文件名,则从标准输入读取输入,并将结果写入标准输出。在没有文件的情况下指定任何--backup-changed--backup-always--backup-ext--create选项是错误的。

选项

-a REGEX, --after-first REGEX

如果文件中没有找到line--regexp,则将line插入到匹配正则表达式REGEX的第一行之后,或者如果没有任何行匹配REGEX,则插入文件末尾。

-A REGEX, --after-last REGEX

如果文件中没有找到line--regexp,则将line插入到匹配正则表达式REGEX的最后一行之后,或者如果没有任何行匹配REGEX,则插入文件末尾。

-b REGEX, --before-first REGEX

如果文件中没有找到line--regexp,则将line插入到匹配正则表达式REGEX的第一行之前,或者如果没有任何行匹配REGEX,则插入文件末尾。

-B REGEX, --before-last REGEX

如果在文件中找不到 line--regexp,则在匹配正则表达式 REGEX 的最后一行之前插入 line,或者在没有匹配到 REGEX 的情况下在文件末尾插入。

--bof

如果在文件中找不到 line--regexp,则在文件开头插入 line

--eof

如果在文件中找不到 line--regexp,则在文件末尾插入 line。这是默认行为。

-e REGEX--regexp REGEX

如果指定的正则表达式与文件中的任何行匹配,则用 line 替换最后一个匹配的行(如果没有指定 --match-first,则为第一行)。

--backrefs

如果 --regexp 匹配,则正则表达式中的捕获组用于扩展 line 中的任何 \n\g<n>\g<name> 回溯引用,并用结果字符串替换输入中的匹配行。

如果 --regexp 不匹配,则输入保持不变。

如果不指定 --regexp 选项,则指定此选项是错误的。

--backup--backup-changed

如果输入文件被修改,则创建原始文件的备份。备份文件的扩展名由 --backup-ext 指定(如果没有指定扩展名,则为 ~)。

--backup-always

无论原始文件是否被修改,都创建备份。备份文件的扩展名由 --backup-ext 指定(如果没有指定扩展名,则为 ~)。

-i EXT--backup-ext EXT

在文件名末尾添加 EXT 以创建输入文件的备份。如果没有指定此选项或 --backup-always,则隐含 --backup-changed

-c--create

如果输入文件不存在,则将其视为空文件而不是错误,并使用操作结果创建文件。对于不存在的文件,无论其他选项如何,都不会创建备份文件。

如果输入文件不存在且没有进行更改(因为指定了 --backrefs--regexp 未匹配),则不会创建文件。

-L LINE--line LINE

使用 LINE 作为要插入的行。当 LINE 以连字符开头时,此选项很有用。

-m--match-first

如果 --regexp 匹配,则用 line 替换第一个匹配的行。

-M--match-last

如果 --regexp 匹配,则用 line 替换最后一个匹配的行。这是默认行为。

-o FILE--outfile FILE

将结果文件内容写入文件,而不是修改输入文件。

--backup-changed--backup-always--backup-ext中的任何选项一起指定此选项是错误的。

删除

lineinfile remove [<options>] <regexp> [<file>]
lineinfile remove [<options>] -e <regexp> [<file>]

删除所有与给定的Python正则表达式匹配的给定文件中的所有行。

如果命令行中没有给出文件名,则从标准输入读取输入,并将结果写入标准输出。当没有给出文件时指定任何--backup-changed--backup-always--backup-ext选项是错误的。

选项

--backup--backup-changed

如果输入文件被修改,则创建原始文件的备份。备份文件的扩展名由 --backup-ext 指定(如果没有指定扩展名,则为 ~)。

--backup-always

无论原始文件是否被修改,都创建备份。备份文件的扩展名由 --backup-ext 指定(如果没有指定扩展名,则为 ~)。

-i EXT--backup-ext EXT

在文件名末尾添加 EXT 以创建输入文件的备份。如果没有指定此选项或 --backup-always,则隐含 --backup-changed

-e REGEX--regexp REGEX

删除所有与REGEX匹配的行。当REGEX以连字符开头时,此选项非常有用。

-o FILE--outfile FILE

将结果文件内容写入文件,而不是修改输入文件。

--backup-changed--backup-always--backup-ext中的任何选项一起指定此选项是错误的。

库API

请注意,所有正则表达式匹配都是使用Pattern.search()方法完成的,即它不是从行的开头锚定的。为了强制正则表达式从行的开头开始匹配,请在其前缀中使用^\A

lineinfile.add_line_to_file(
    filepath: Union[str, bytes, os.PathLike[str], os.PathLike[bytes]],
    line: str,
    regexp: Optional[Union[str, re.Pattern[str]]] = None,
    inserter: Optional[Inserter] = None,
    match_first: bool = False,
    backrefs: bool = False,
    backup: Optional[BackupWhen] = None,
    backup_ext: Optional[str] = None,
    create: bool = False,
    encoding: Optional[str] = None,
    errors: Optional[str] = None,
) -> bool

如果给定的在文件中不存在,则将其添加到filepath文件中。如果文件被修改,则返回True。如果regexp设置为正则表达式(字符串或编译后的模式对象),并且它与文件中的任何行匹配,则line将替换最后一个匹配行(或如果match_first=True,则为第一个匹配行)。如果正则表达式不匹配任何行(或没有指定正则表达式)并且line在文件中未找到,则默认情况下将行插入文件末尾;这可以通过传递适当的对象作为inserter参数来更改;请参见下方的“插入器”。

backrefs为true时,如果regexp匹配,则正则表达式中的捕获组用于扩展line中的任何\n\g<n>\g<name>回引用,并且结果字符串替换输入中匹配的行。如果backrefs为true且regexp不匹配,则文件保持不变。如果没有同时设置regexp,则将backrefs设置为true是错误的。

backup设置为lineinfile.CHANGED时,如果文件被修改,将创建文件原始内容的备份。当backup设置为lineinfile.ALWAYS时,无论文件是否被修改,都会创建备份。备份文件的名称将与原始文件相同,并在末尾附加backup_ext的值(默认:~)。

如果 create 为 true 且 filepath 不存在,则模拟为空文件而不是报错,并使用操作结果创建文件。对于不存在的文件,永远不会创建备份文件。如果 filepath 不存在且没有进行任何更改(因为 backrefs 被设置且 regexp 不匹配),则不会创建文件。

lineinfile.remove_lines_from_file(
    filepath: Union[str, bytes, os.PathLike[str], os.PathLike[bytes]],
    regexp: Union[str, re.Pattern[str]],
    backup: Optional[BackupWhen] = None,
    backup_ext: Optional[str] = None,
    encoding: Optional[str] = None,
    errors: Optional[str] = None,
) -> bool

删除位于 filepath 的文件中所有匹配正则表达式 regexp(可以是字符串或编译后的模式对象)的行。如果文件被修改,则返回 True

backup设置为lineinfile.CHANGED时,如果文件被修改,将创建文件原始内容的备份。当backup设置为lineinfile.ALWAYS时,无论文件是否被修改,都会创建备份。备份文件的名称将与原始文件相同,并在末尾附加backup_ext的值(默认:~)。

lineinfile.add_line_to_string(
    s: str,
    line: str,
    regexp: Optional[Union[str, re.Pattern[str]]] = None,
    inserter: Optional[Inserter] = None,
    match_first: bool = False,
    backrefs: bool = False,
) -> str

如果给定的 line 还未存在于字符串 s 中,则将其添加到字符串中并返回结果。如果 regexp 设置为正则表达式(可以是字符串或编译后的模式对象)并且它匹配任何输入行,则 line 将替换最后匹配的行(如果 match_first=True,则替换第一个匹配的行)。如果正则表达式不匹配任何行(或未指定正则表达式)并且 line 在输入中未找到,则默认将其插入到输入的末尾;这可以通过传递适当的对象作为 inserter 参数来更改;请参阅下文的“Inserters”。

backrefs 为 true 时,如果 regexp 匹配,则正则表达式中的捕获组用于展开 line 中的任何 \n\g<n>\g<name> 反向引用,并替换输入中匹配的行。如果 backrefs 为 true 且 regexp 不匹配,则输入保持不变。未设置 regexp 而仅设置 backrefs 为 true 是一个错误。

lineinfile.remove_lines_from_string(
    s: str,
    regexp: Union[str, re.Pattern[str]],
) -> str

删除字符串 s 中所有匹配正则表达式 regexp(可以是字符串或编译后的模式对象)的行并返回结果。

插入器

插入器是 add_line_* 函数使用的对象,用于确定在输入中未找到 line 并且如果设置了 regexp 参数,则不匹配任何行时插入 line 的位置。

lineinfile 提供以下插入器类

AtBOF()

始终将行插入到文件的开头

AtEOF()

始终将行插入到文件的末尾

AfterFirst(regexp)

将行插入到第一个匹配给定正则表达式(可以是字符串或编译后的模式对象)的输入行之后,如果没有匹配的行,则插入到文件末尾。

AfterLast(regexp)

将行插入到最后一个匹配给定正则表达式(可以是字符串或编译后的模式对象)的输入行之后,如果没有匹配的行,则插入到文件末尾。

BeforeFirst(regexp)

将行插入到第一个匹配给定正则表达式(可以是字符串或编译后的模式对象)的输入行之前,如果没有匹配的行,则插入到文件末尾。

BeforeLast(regexp)

将行插入到最后一个匹配给定正则表达式(可以是字符串或编译后的模式对象)的输入行之前,如果没有匹配的行,则插入到文件末尾。

行结束符的处理

lineinfile 使用 Python 的通用换行符模式来处理文件,在该模式下,当文件中的所有 LF (\n)、CR LF (\r\n) 和 CR (\r) 序列被读取到 Python 字符串时,都会被转换为仅 LF。当数据被写回磁盘时,LF 又会被转换为操作系统本地的行分隔符。

在大多数情况下,这允许你在正则表达式中使用 $ 符号,使其始终匹配输入行的末尾,而不管该行在磁盘上的行结束符是什么。然而,当使用 add_line_to_string()remove_lines_from_string() 函数处理包含非 LF 行分隔符的字符串时,事情可能会变得复杂。关于行分隔符,lineinfile 遵循以下规则:

  • 行以 LF、CR 和 CR LF 结尾。

  • add_line_* 函数将 line 参数与输入中的行进行比较时,会从两个行中都移除行结束符。这与 Ansible 的行为不同,Ansible 只移除输入行的行结束符。

  • 当将输入行与 regexp 或插入器进行匹配时,不会移除行结束符。注意,像 r"foo$" 这样的正则表达式不会匹配以非 LF 行结束符结束的行,因此这可能导致模式无法匹配你天真地期望它们匹配的地方。

  • 当将行添加到文件末尾时,如果文件末尾没有行结束符,则在添加行之前会追加一个 LF。

  • 当将 line 添加到文档中(无论是作为新行还是替换现有的行)时,如果行末没有行分隔符,则会在行末追加 LF;如果被替换的行(如果有)中有行结束符,则忽略它(如果你想保留它,请使用反向引用)。如果结果 line 与被替换的行之间唯一的区别是行结束符,则替换仍然发生,行结束符被修改,文档被更改。

项目详情


下载文件

下载适合您平台的应用文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源分发

lineinfile-0.4.0.tar.gz (30.9 kB 查看哈希值)

上传时间 源代码

构建分发

lineinfile-0.4.0-py3-none-any.whl (13.6 kB 查看哈希值)

上传时间 Python 3

由以下支持