I have a requirement to update a configuration file content at a specific lines location. How to do this in python. For example, I have a configuration file which is having below 5 lines now: 

define host{
    name kiki-server;
    XXXX XXXX;
    XXXX XXXX;
    }

I am interested have my python script to add new define statement for a new host only if the host name is not yet define in the configuration file. For example, if I run my python script to add "bouncy-server", it will append another 5 lines above this existing content. What built-in functions can help? I studied File methods, but it is missing the ability to place cursor to write new contents line to be above existing "define host{" line.    

Dani AI

Generated

A short, practical note for : the usual safe pattern is not to try to "insert" in-place (file objects do not support inserting bytes in the middle) but to read, modify in memory or stream, and write back atomically. ' string-slicing idea is fine for small one-off edits, but it can break if the exact substring/spacing differs (his example used "define hosts{" while your sample used "define host{"), or if there are multiple define blocks.

A robust approach:

  • read the file as lines,
  • use a regex to look for an existing name <host>; entry and bail out if found,
  • locate the first define host block (accept minor whitespace or pluralization with a regex) and insert your block just before it (or append if none),
  • write the result to a temporary file and atomically replace the original (preserve permissions and make a backup first).

The snippet below implements that pattern (it accepts the new host block as a list of lines):

import re
import tempfile
import shutil
import os

def add_host_file(path, host_name, host_block_lines):
    with open(path, 'r', encoding='utf-8') as f:
        lines = f.readlines()

    name_re = re.compile(r'^\s*name\s+' + re.escape(host_name) + r'\s*;', re.I)
    if any(name_re.search(l) for l in lines):
        return False  # already present

    def_re = re.compile(r'^\s*define\s+hosts?\s*\{', re.I)
    insert_at = next((i for i,l in enumerate(lines) if def_re.search(l)), len(lines))

    block = [(ln if ln.endswith('\n') else ln + '\n') for ln in host_block_lines]
    new_lines = lines[:insert_at] + block + lines[insert_at:]

    shutil.copy2(path, path + '.bak')
    st = os.stat(path)
    tf = tempfile.NamedTemporaryFile('w', delete=False, encoding='utf-8')
    try:
        tf.writelines(new_lines)
        tf.flush(); tf.close()
        os.chmod(tf.name, st.st_mode)
        shutil.copystat(path, tf.name)
        os.replace(tf.name, path)
    finally:
        if os.path.exists(tf.name):
            os.remove(tf.name)
    return True

Quick tips: test on a copy and keep backups; use file locking if multiple processes might edit the file concurrently; if the config language has nested semantics, prefer a parser instead of regexes.

Recommended Answers

All 2 Replies

A configuration file is usually a reasonably sized file, and you can load its content in memory as a python string or a python list of lines. You could cut this string and insert your new content as in this example:

>>> s = "foo a e ueiue uie uie define hosts{ eu ett ul uieue"
>>> idx = s.index('define hosts{')
>>> head, tail = s[:idx], s[idx:]
>>> head
'foo a e ueiue uie uie '
>>> tail
'define hosts{ eu ett ul uieue'
>>> middle = 'foo bar baz qux \n'
>>> head + middle + tail
'foo a e ueiue uie uie foo bar baz qux \ndefine hosts{ eu ett ul uieue'

Thanks for your suggestion. The string index method can help me to modify the configuration file.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.