Package: lineinfile
GitHub|PyPI|Issues|ChangelogInspired by (but not affiliated with)the Ansible module of the same name,lineinfileprovides a command and library for adding a line to a file if
it’s not already there and for removing lines matching a pattern from a file.
There are options for using a regex to find a line to update or to determine
which line to insert before or after.  There are options for backing up the
modified file with a custom file extension and for treating a nonexistent file
as though it’s just empty.  There’s even an option for determining the line to
insert based on capturing groups in the matching regex.Unlike the Ansible module, this package does not perform any management of file
attributes; those must be set externally.Installationlineinfilerequires Python 3.6 or higher.  Just usepipfor Python 3 (You have pip, right?) to installlineinfileand its dependencies:python3 -m pip install lineinfileExamplesA crude.ini-file updater: Settheoptiontovalue, and if no
setting fortheoptionis found in the file, add one after the line
“[thesection]”:$lineinfileadd\--after-first"^\[thesection\]$"\-e"^theoption\s*="\"theoption = thevalue"\settings.iniThe equivalent operation in Python:fromlineinfileimportAfterFirst,add_line_to_fileadd_line_to_file("settings.ini","theoption = thevalue",regexp=r"^theoption\s*=",inserter=AfterFirst(r"^\[thesection\]$"),)Replace the first instance of “foo = ...” with “foo = 'bar'”,
preserving indentation, and create a backup of the file with the extension.bak, even if no changes were made:$lineinfileadd\-e"^(\s*)foo\s*="\--backrefs\--match-first\--backup-always-i.bak\"\1foo = 'bar'"\file.pyThe equivalent operation in Python:fromlineinfileimportALWAYS,add_line_to_fileadd_line_to_file("file.py",r"\1foo = 'bar'",regexp=r"^(\s*)foo\s*=",backrefs=True,match_first=True,backup=ALWAYS,backup_ext=".bak",)Command-Line UsageThelineinfilecommand has two subcommands,addandremove.addlineinfile add [<options>] <line> [<file>]
lineinfile add [<options>] -L <line> [<file>]Add the givenline(after expanding backslash escapes) to the file if it is
not already present.  If aPython regular expressionis given with the-e/--regexpoption and it matches any lines in the file,linewill
replace the last matching line (or the first matching line, if--match-firstis given).  If the regular expression does not match any
lines (or no regular expression is specified) andlineis not found in the
file, the line is inserted at the end of the file by default; this can be
changed with the--after-first,--after-last,--before-first,--before-last, and--bofoptions.If no file name is given on the command line, input is read from standard
input, and the result is written to standard output.  It is an error to specify
any of the--backup-changed,--backup-always,--backup-ext, or--createoptions when no file is given.Options-aREGEX,--after-firstREGEXIf neitherlinenor--regexpis found in
the file, insertlineafter the first line that
matches the regular expressionREGEX, or at the
end of the file if no line matchesREGEX.-AREGEX,--after-lastREGEXIf neitherlinenor--regexpis found in
the file, insertlineafter the last line that
matches the regular expressionREGEX, or at the
end of the file if no line matchesREGEX.-bREGEX,--before-firstREGEXIf neitherlinenor--regexpis found in
the file, insertlinebefore the first line
that matches the regular expressionREGEX, or
at the end of the file if no line matchesREGEX.-BREGEX,--before-lastREGEXIf neitherlinenor--regexpis found in
the file, insertlinebefore the last line that
matches the regular expressionREGEX, or at the
end of the file if no line matchesREGEX.--bofIf neitherlinenor--regexpis found in
the file, insertlineat the beginning of the
file.--eofIf neitherlinenor--regexpis found in
the file, insertlineat the end of the file.
This is the default.-eREGEX,--regexpREGEXIf the given regular expression matches any lines
in the file, replace the last matching line (or
first, if--match-firstis given) withline.--backrefsIf--regexpmatches, the capturing groups in
the regular expression are used to expand any\n,\g<n>, or\g<name>backreferences
inline, and the resulting string replaces the
matched line in the input.If--regexpdoes not match, the input is left
unchanged.It is an error to specify this option without--regexp.--backup,--backup-changedIf the input file is modified, create a backup of
the original file.  The backup will have the
extension specified with--backup-ext(or~if no extension is specified) appended to its
filename.--backup-alwaysCreate a backup of the original file regardless of
whether or not it’s modified.  The backup will have
the extension specified with--backup-ext(or~if no extension is specified) appended to its
filename.-iEXT,--backup-extEXTCreate a backup of the input file withEXTadded to the end of the filename.  Implies--backup-changedif neither it nor--backup-alwaysis also given.-c,--createIf the input file does not exist, pretend it’s
empty instead of erroring, and create it with the
results of the operation.  No backup file will be
created for a nonexistent file, regardless of the
other options.If the input file does not exist and no changes are
made (because--backrefswas specified and--regexpdidn’t match), the file will not be
created.-LLINE,--lineLINEUseLINEas the line to insert.  This option is
useful whenLINEbegins with a hyphen.-m,--match-firstIf--regexpmatches, replace the first matching
line withline.-M,--match-lastIf--regexpmatches, replace the last matching
line withline.  This is the default.-oFILE,--outfileFILEWrite the resulting file contents toFILEinstead of modifying the input file.It is an error to specify this option with any of--backup-changed,--backup-always, or--backup-ext.removelineinfile remove [<options>] <regexp> [<file>]
lineinfile remove [<options>] -e <regexp> [<file>]Delete all lines from the given file that match the givenPython regular
expression.If no file name is given on the command line, input is read from standard
input, and the result is written to standard output.  It is an error to specify
any of the--backup-changed,--backup-always, or--backup-extoptions when no file is given.Options--backup,--backup-changedIf the input file is modified, create a backup of
the original file.  The backup will have the
extension specified with--backup-ext(or~if no extension is specified) appended to its
filename.--backup-alwaysCreate a backup of the original file regardless of
whether or not it’s modified.  The backup will have
the extension specified with--backup-ext(or~if no extension is specified) appended to its
filename.-iEXT,--backup-extEXTCreate a backup of the input file withEXTadded to the end of the filename.  Implies--backup-changedif neither it nor--backup-alwaysis also given.-eREGEX,--regexpREGEXDelete all lines that matchREGEX.  This option
is useful whenREGEXbegins with a hyphen.-oFILE,--outfileFILEWrite the resulting file contents toFILEinstead of modifying the input file.It is an error to specify this option with any of--backup-changed,--backup-always, or--backup-ext.Library APINote that all regular expression matching is done with thePattern.search()method, i.e., it is not anchored at the start of the line.  In order to force a
regular expression to start matching at the beginning of a line, prefix it with^or\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,)->boolAdd the givenlineto the file atfilepathif it is not already
present.  ReturnsTrueif the file is modified.  Ifregexpis set to a
regular expression (either a string or a compiled pattern object) and it
matches any lines in the file,linewill replace the last matching line (or
the first matching line, ifmatch_first=True).  If the regular expression
does not match any lines (or no regular expression is specified) andlineis not found in the file, the line is inserted at the end of the file by
default; this can be changed by passing the appropriate object as theinserterargument; see “Inserters” below.Whenbackrefsis true, ifregexpmatches, the capturing groups in the
regular expression are used to expand any\n,\g<n>, or\g<name>backreferences inline, and the resulting string replaces the matched line
in the input.  Ifbackrefsis true andregexpdoes not match, the file
is left unchanged.  It is an error to setbackrefsto true without also
settingregexp.Whenbackupis set tolineinfile.CHANGED, a backup of the file’s
original contents is created if the file is modified.  Whenbackupis set
tolineinfile.ALWAYS, a backup is always created, regardless of whether the
file is modified.  The name of the backup file will be the same as the
original, with the value ofbackup_ext(default:~) appended.Ifcreateis true andfilepathdoes not exist, pretend it’s empty
instead of erroring, and create it with the results of the operation.  No
backup file will ever be created for a nonexistent file.  Iffilepathdoes
not exist and no changes are made (becausebackrefswas set andregexpdidn’t match), the file will not be created.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,)->boolDelete all lines from the file atfilepaththat match the regular
expressionregexp(either a string or a compiled pattern object).  ReturnsTrueif the file is modified.Whenbackupis set tolineinfile.CHANGED, a backup of the file’s
original contents is created if the file is modified.  Whenbackupis set
tolineinfile.ALWAYS, a backup is always created, regardless of whether the
file is modified.  The name of the backup file will be the same as the
original, with the value ofbackup_ext(default:~) appended.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,)->strAdd the givenlineto the stringsif it is not already present and
return the result.  Ifregexpis set to a regular expression (either a
string or a compiled pattern object) and it matches any lines in the input,linewill replace the last matching line (or the first matching line, ifmatch_first=True).  If the regular expression does not match any lines (or
no regular expression is specified) andlineis not found in the input, the
line is inserted at the end of the input by default; this can be changed by
passing the appropriate object as theinserterargument; see “Inserters”
below.Whenbackrefsis true, ifregexpmatches, the capturing groups in the
regular expression are used to expand any\n,\g<n>, or\g<name>backreferences inline, and the resulting string replaces the matched line
in the input.  Ifbackrefsis true andregexpdoes not match, the input
is left unchanged.  It is an error to setbackrefsto true without also
settingregexp.lineinfile.remove_lines_from_string(s:str,regexp:Union[str,re.Pattern[str]],)->strDelete all lines from the stringsthat match the regular expressionregexp(either a string or a compiled pattern object) and return the
result.InsertersInserters are objects used by theadd_line_*functions to determine the
location at which to insertlinewhen it is not found in the input and theregexpargument, if set, doesn’t match any lines.lineinfileprovides the following inserter classes:AtBOF()Always inserts the line at the beginning of the fileAtEOF()Always inserts the line at the end of the fileAfterFirst(regexp)Inserts the line after the first input line that matches the given regular
expression (either a string or a compiled pattern object), or at the end of
the file if no line matches.AfterLast(regexp)Inserts the line after the last input line that matches the given regular
expression (either a string or a compiled pattern object), or at the end of
the file if no line matches.BeforeFirst(regexp)Inserts the line before the first input line that matches the given regular
expression (either a string or a compiled pattern object), or at the end of
the file if no line matches.BeforeLast(regexp)Inserts the line before the last input line that matches the given regular
expression (either a string or a compiled pattern object), or at the end of
the file if no line matches.Handling of Line Endingslineinfileoperates on files using Python’s universal newlines mode, in
which all LF (\n), CR LF (\r\n), and CR (\r) sequences in a file
are converted to just LF when read into a Python string, and LF is in turn
converted to the operating system’s native line separator when written back to
disk.In the majority of cases, this allows you to use$in regular expressions
and have it always match the end of an input line, regardless of what line
ending the line had on disk.  However, when usingadd_line_to_string()orremove_lines_from_string()with a string with non-LF line separators,
things can get tricky.lineinfilefollows the following rules regarding
line separators:Lines are terminated by LF, CR, and CR LF only.When anadd_line_*function compares alineargument against a line
in the input, the line ending is stripped from both lines.  This is a
deviation from Ansible’s behavior, where only the input line is stripped.When matching an input line againstregexpor an inserter, line endings
are not stripped.  Note that a regex liker"foo$"will not match a line
that ends with a non-LF line ending, so this can result in patterns not
matching where you might naïvely expect them to match.When adding a line to the end of a file, if the file does not end with a line
ending already, an LF is appended before adding the line.When addinglineto a document (either as a new line or replacing a
pre-existing line), LF is appended to the line if it does not already end
with a line separator; any line ending on the line being replaced (if any) is
ignored (If you want to preserve it, use backrefs).  If the only difference
between the resultinglineand the line it’s replacing is the line
ending, the replacement still occurs, the line ending is modified, and the
document is changed.