Python: append between pattern

edited October 2022 in Help

So, I continue my learning with python by rewriting 2k+ lines of bash beauty. And now struggling with real bad ass problem: pythons inability to manipulate text in files. Just astonishing how complicated it is.

Have bash function:

ip_access() {

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

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

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

   # format IPs into .htaccess acceptable format
    arrip=()
    for ip in ${ips//,/ }; do
        arrip+=("Require ip $ip\n")
    done

    # remove everything
    sed -i '/##ip_access1/,/##ip_access2/{d}' "${htaccess}"

    # inject fresh batch
    { 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!"
}

This function appends text into .htaccess file in this format:

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

If no IPs provided function just removes everything between ##ip_access1 and ##ip_access2 including the pattern.

How to achieve this with Python? Any clues?

Comments

  • edited October 2022

    @legendary said: If no IPs provided function just removes everything between ##ip_access1 and ##ip_access2 including the pattern.

    It's a tad late (6:00 AM lol), so I'll leave a naive solution below. You (obviously) don't want to be reading a massive .htaccess file into memory (we should be manipulating it as a stream as opposed to loading the file into memory). (I didn't implement all the functionality listed, but they should be pretty simple to do.)

    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
    
    Thanked by (1)legendary
  • Holy F, this line is pure magic:

    return "\n".join(lines[0:pos1]) + start + to_replace + end + "\n".join(lines[pos2 + 1:len(lines)])

  • @legendary said:
    Holy F, this line is pure magic:

    return "\n".join(lines[0:pos1]) + start + to_replace + end + "\n".join(lines[pos2 + 1:len(lines)])

    Glad I could help! :-)

Sign In or Register to comment.