Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Append a line in file with given input arguments using python

I have a YAML file with the content below:

job_name: "node"
scrape_interval: "15s"
static_configs:
  -  targets: ['10.10.10.11:8080']

now if I execute my python script it should append target line in YAML file using given arguments

i.e script.py -ip 10.10.20.30 -p 8181

file should look like this

job_name: "node"
scrape_interval: "15s"
static_configs:
  -  targets: ['10.10.10.11:8080', '10.10.20.30:8181']

for this I am using the python script below, but it's giving errors:

#!/usr/bin/python

import os
import yaml

with open('test.yaml', 'ra') as f:
    lines = f.readlines()
    for i, line in enumerate(lines):
        if line.startswith('targets:'):
            line[i] = line[i].strip() + 'arg1,arg2\n'
    f.seek(0)
    for line in lines:
        f.write(line)

How can I fix this?

like image 612
Byreddy Sahithi Reddy Avatar asked Jun 26 '26 20:06

Byreddy Sahithi Reddy


1 Answers

You are importing os, yaml (i.e. PyYAML) but you are not using those packages.

You also try to "edit" the YAML file as if it is unstructured text, and you should not. Instead you should load the YAML file, then extend the data structure that you get and then dump the data structure back to the YAML file, but not with PyYAML as that doesn't support this kind of round-tripping without losing information.

Instead use ruamel.yaml (disclaimer: I am the author of that package):

from ruamel.yaml import YAML

yaml = YAML()
yaml.preserve_quotes = True
yaml.indent = 5
yaml.block_seq_indent = 2

ip = '10.10.20.30'  # sys.argv[2]
port = 8181         # sys.argv[4]

with open('test.yaml') as f:
    data = yaml.load(f)
    targets = data['static_configs'][0]['targets']
    targets.append(type(targets[0])(str(ip) + ':' + str(port)))

with open('test.yaml', 'w') as fo:
    yaml.dump(data, fo)

Which will write:

job_name: "node"
scrape_interval: "15s"
static_configs:
  -  targets: ['10.10.10.11:8080', '10.10.20.30:8181']

Setting attributes preserve_quotes, indent, block_seq_indent is only needed to get the output to match your input. So is the copying of the type of the first targets element. Actually none of the quotes in your file are needed.

If a more default YAML output file, which will load to the same data, is ok with you can do:

from ruamel.yaml import YAML

yaml = YAML()

ip = '10.10.20.30'  # sys.argv[2]
port = 8181         # sys.argv[4]

with open('test.yaml') as f:
    data = yaml.load(f)
    data['static_configs'][0]['targets'].append(str(ip) + ':' + str(port))

with open('test.yaml', 'w') as fo:
    yaml.dump(data, fo)

Please note that both the key order in multiple entry mappings, as well as any comments in your YAML file would be preserved by the above round-tripping.

You would of course still have to get the IP and port from the commandline, and concatenate the values instead of hard coding the ip and port values. I suggest using the standard python module argparse for that, but beware that most applications only take long options with double dashes (--ip instead of -ip)

like image 197
Anthon Avatar answered Jun 29 '26 11:06

Anthon