通过正则表达式在文件中添加和删除行
项目描述
受(但不隶属于)同名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命令有两个子命令,add和remove。
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 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | b300df2da429065e81568f335bc78ac16c323296e3da65eee3b790e48d26d747 |
|
MD5 | 108dc85951f4eab602fc66738189fe77 |
|
BLAKE2b-256 | 03398351150dcf835b425f78b59ed6daca2363b39f6afac3003928ef838571c7 |