2

Well this is my script. It is to configure my systems sysctl.conf.

infile = open('sysctl.conf')
outfile = open('sysctl.conf.new', 'w')

replacements = {'Net.ipv4.icmp_echo_ignore_all' :'1',
            'Net.ipv4.icmp_echo_ignore_broadcasts' :'1',
            'Net.ipv4.ip_forward' : '0',
            'Net.ipv4.tcp_syncookies':'1',
            'Net.ipv4.conf.all.rp_filter': '1',
            'Net.ipv4.conf.all.Log.martiansd':'1',
            'Net.ipv4.conf.all.Secure_redirects' : '1',
            'Net.ipv4.conf.all.Send_redirects' : '0',
            'Net.ipv4.conf.all.Accept_Source_Route':  '0',
            'Net.ipv4.conf.all.Accept_redirects':'0',
            'Net.ipv4.tcp_max_syn_backlog': '4096',
            }

for line in infile:
    if '#' in line:
        pass
    elif '=' in line:
        w = line.split('=')
        for var, value in replacements.iteritems():
            if var in w[0]:
                line=line.replace(w[1],value)
    outfile.write(line)
infile.close()
outfile.close()

This script works fine but there is one problem. If any of the parameters in replacement is not present in sysctl.conf then it is not going to add it in the new configuration file.It only modifies the parameters present with my values. I want to add all parameters in the configuration or change if they are already present. How to do it?

I know it should be easy but I am stuck here.

4
  • Have you taken a look at ConfigParser?
    – iruvar
    Commented Jul 22, 2014 at 12:42
  • yes. ConfigParser is good when there are sections in configurations. But many linux configurations don't have sections in them. Also many configurations don't have a '=' in them for which ConfigParser will not work.
    – Shaels
    Commented Jul 22, 2014 at 12:48
  • 1
    I am not proposing ConfigParser as a general panacea for linux configuration parsing; just stating that it may be appropriate for your use case since your file appears to contain key-value pairs with key and value separated by =. As for the section problem, here's a workaround from the great Alex Martelli
    – iruvar
    Commented Jul 22, 2014 at 12:52
  • Thanks, I think that will do what I want. But what should I do for configurations which don't have = in them?
    – Shaels
    Commented Jul 22, 2014 at 12:58

2 Answers 2

2

I would probably do something like this:

testing = True

if testing: ##################################################################

    infile = '''
key0=0
key1=1
 key1 = 1
key2=2 # comment1
#key3=3
  #key4=4
#key5=5 # comment
  #key6=6 # comment
key7=7

key8 = 8
    '''

    infilelines = infile.split('\n')


    class of():
        def write(self, s):
            print s
        def close(self):
            pass
    outfile = of()

    replacements = {
        'key1' :'11repl',
        'key2' :'22repl',
        'key3' :'33repl',
        'key4' :'44repl',
        'key5' :'55repl',
        'key6' :'66repl',
        }


else: #########################################################################

    # as proposed by csny, only open file quickly
    # (file is closed after with statement)
    with open('sysctl.conf') as infile:
        infilelines = infile.readlines()

    outfile = open('sysctl.conf.new', 'w')

    replacements = {'Net.ipv4.icmp_echo_ignore_all' :'1',
        'Net.ipv4.icmp_echo_ignore_broadcasts' :'1',
        'Net.ipv4.ip_forward' : '0',
        'Net.ipv4.tcp_syncookies':'1',
        'Net.ipv4.conf.all.rp_filter': '1',
        'Net.ipv4.conf.all.Log.martiansd':'1',
        'Net.ipv4.conf.all.Secure_redirects' : '1',
        'Net.ipv4.conf.all.Send_redirects' : '0',
        'Net.ipv4.conf.all.Accept_Source_Route':  '0',
        'Net.ipv4.conf.all.Accept_redirects':'0',
        'Net.ipv4.tcp_max_syn_backlog': '4096',
        }



for line in infilelines:

    # if # at the beginning (neglecting whitespaces): its only a line comment
    # write it directly to outfile and continue with next line
    if len(line.strip())==0 or line.strip()[0] == '#':
        outfile.write(line.strip())
        continue

    # try if this is a properly formated line like: key=val
    try:
        key, val = line.split('=')
        key = key.strip()
        val = val.strip()

    # something stange happend: It was not a proper key=val line
    # dont modify anything, just write the line to the new file
    except ValueError:
        # or comment out outfile.write to delete the strange line
        # from the output config file
        outfile.write(line)
        continue

    # maybe you want to allow line end comments like: key=val # comment?
    # lets try if the value actually contains a comment
    try:
        val, comment = val.split('#')
        comment = '# ' + comment.strip()
        val = val.strip()

    # there is no comment at the end of the line
    # (the val.split() returns only one value and thus the unpacking fails with:
    # ValueError: need more values to unpack)
    except ValueError:
        comment = ''


    # replace the val if the according key in the `replacements` dict
    # with the value stored in the key
    # otherwise don't change anything
    if key in replacements.keys():
        val = replacements[key]

    # put together the new line for the output file
    line = '%s=%s   %s' % (key, val, comment)
    outfile.write(line)

outfile.close()

See comments in the code. This takes the config line apart, changes the value if the key exists in the dict, and finally reassenbles the line to print to the out file. This also allows to have comments at the line endings.

4
  • please note my edit: you should also check for empty line in first if.. also, this won't conserve spaces in your config file. that would need a bit more work..
    – RafiK
    Commented Jul 22, 2014 at 13:30
  • and maybe you want to add key = key.strip() so keys with leading / trailing whitespaces also work..
    – RafiK
    Commented Jul 22, 2014 at 14:02
  • well it is working fine if the key is present in replacement array but if the key is not present in replacement array it is not adding it. how to solve that?
    – Shaels
    Commented Jul 28, 2014 at 13:19
  • can you add a small example from the sysctl.conf file (maybe add to the question, using pastebin or similar) such that I can test what should work? Because it works with my test: gist.github.com/RafiKueng/042b987c01acce4a50b4
    – RafiK
    Commented Jul 29, 2014 at 12:59
1

Few comments about your code:

  1. If you want to easily insert configuration from "replacements" if it doesn't exist, consider iterating each "replacement" over the lines of the file instead of each line of the file over "replacements". This way, if you don't find any replacement key in the lines, construct and write a new configuration line.
  2. I would rather use "readlines()" and close sysctl.conf in order to free the sysctl.conf file instead of holding it open. If other processes use sysctl, while you're running this, it might harm your configurations.
  3. You're parsing sysctl.conf file, which contains lines either starting with a "#", or as key = value. no comments after values exist.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.