Python append text between lines

Question:

The task:

I have list of IPs which needs to be added to the .htaccess files in this format:

##ip_access1
Require ip 127.0.0.1
Require ip 127.0.0.2
Require all denied
##ip_access2

The problem:

How to append text into .htaccess file with Python? I know how to do this with bash, but I need Python specifically for now.

Cases:

  1. If tuple of IPs is empty, find pattern ##ip_access1 ##ip_access2 and delete everything between them including the pattern in the file;
  2. If .htaccess file is not empty, append ##ip_access1 <…> ##ip_access2 to the bottom of the file with all IPs;

P.S. Bash implementation.

ip_access() {

    local user=$1
    local htaccess="/var/www/${user}/site/.htaccess"
    local ips="$2"

    # manipulate records in .htaccess
    [ ! -f "${htaccess}" ] && touch "${htaccess}"

    if [ -z "${ips}" ]; then
        sed -i '/##ip_access1/,/##ip_access2/{d}' "${htaccess}"
        chown "${user}":"${user}" "${htaccess}"
        echo "IP access successfully reset!"
        exit 0
    fi

    arrip=()
    for ip in ${ips//,/ }; do
        arrip+=("Require ip $ipn")
    done

    # always inject fresh batch of ips
    sed -i '/##ip_access1/,/##ip_access2/{d}' "${htaccess}"
    { echo -e "##ip_access1";
     echo -e "${arrip:?}" | head -c -1;
     echo -e "Require all denied";
     echo -e "##ip_access2"; } >> "${htaccess}"

    chown "${user}":"${user}" "${htaccess}"

    echo "IP access successfully set!"
}
Asked By: Roman01

||

Answers:

This function is the bare bones of a possible solution. It doesn’t perform any sanity checks so caution should be exercised.

import os

def ips_to_file(ips, file_path):
    if len(ips) > 0:
        ip_lines = ['##ip_access1'] + [f'Require ip {ip}' for ip in ips] + ['Require all denied', '##ip_access2']
    else:
        ip_lines = []
    if os.path.isfile(file_path):
        with open(file_path, 'r+') as fp:
            lines = [line.strip() for line in fp.readlines()]
            lines = lines[:lines.index('##ip_access1')] + ip_lines + lines[lines.index('##ip_access2')+1:]
            fp.seek(0)
            fp.truncate()
            fp.writelines(lines)
Answered By: Dan Nagle

Found solution with help of course:

from typing import *

ip_lst = ["1.1.1.1", "2.2.2.2", "3.3.3.3"]

htaccess_file_contents = open("test.txt", "r").read()

def _generate_htaccess_compat_lst(lst) -> str:
    to_return = []
    for addr in lst: 
        to_return.append("Require ip " + addr)
    return "n{}n".format("n".join(to_return))

def _inject_between(start, end, to_manipulate, to_replace) -> str:
    lines = to_manipulate.splitlines()
    counter = 0
    pos1, pos2 = -1, -1
    # find lines between that we need to replace
    for line in lines:
        if start == line:
            pos1 = counter
        elif end == line:
            pos2 = counter
        counter += 1
    # return null if we can't find text between
    if pos1 == -1 or pos2 == -1:
        return None
    # +1 to offset the last line as the first index is inclusive
    return "n".join(lines[0:pos1]) + start + to_replace + end + "n".join(lines[pos2 + 1:len(lines)])

tmp = _inject_between("##ip_access1", "##ip_access2", 
    htaccess_file_contents, 
    _generate_htaccess_compat_lst(ip_lst))

print(tmp)

# feel free to write tmp back to .htaccess
Answered By: Roman01
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.