1

I'm trying to do the following:

I have this file called testing.txt that I want to update each time the ip address or addresses change based on the name (test1ip, test2ip):

127.0.0.1 localhost
somotherrandomip testing
192.168.0.36 test1ip
192.168.0.37 test2ip

This is what I've tried.

#!/bin/bash
array=(
        "192.168.0.34 test1ip"
        "192.168.0.35 test2ip"
)

for i in "${array[@]}"; do
        if ! grep -Fxq "$i" testing.txt
        then
                echo "ip-name=$i is not present, so adding it in testing.txt file" 
                echo "$i" >> testing.txt
        else
                echo "ip-name=$i is present in file, so nothing to do"
        fi
done

However, this script appends a completely new line if the line is not found. What I would like to achieve is to overwrite the line if test1ip or test2ip is found but the ip address change.

Expected result:

127.0.0.1 localhost
somotherrandomip testing
192.168.0.34 test1ip
192.168.0.35 test2ip

I've also read this How to check if a string contains a substring in Bash but it seems i can't figure it out.

Any help is greatly appreciated!

0

2 Answers 2

2

The following works on my machine. I changed the array to an associative array, removed the -x option to grep, and used sed to edit the file in place.

#!/bin/bash

#associative array
declare -A array=(
        [test1ip]="192.168.0.34"
        [test2ip]="192.168.0.35"
)

#Loop over keys of the array
#See parameter expansion in bash manpage
for i in "${!array[@]}"; do
        if ! grep -Fq "$i" testing.txt
        then
                echo "ip-name=$i is not present, so adding it in testing.txt file" 
                echo "${array[$i]} $i" >> testing.txt
        else
                echo "ip-name=$i is present in file so running sed"

                #Escape sed left hand side
                #Adapted for extended regular expressions from https://unix.stackexchange.com/a/129063/309759
                i=$(printf '%s\n' "$i" | sed 's:[][\\/.^$*+?(){}|]:\\&:g')

                #Excape right hand side
                ipaddr=$(printf '%s\n' "${array[$i]}" | sed 's:[\\/&]:\\&:g;$!s/$/\\/')

                #Replace old IP vith new IP
                sed -Ei "s/[0-9]+(\.[0-9]+){3} +$i/$ipaddr $i/" testing.txt
        fi
done
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks @Nathan for helping out on this.
You might need to escape the hostnames for using them in sed as string literals; for example example.test will match examplestest. Also, while you correctly fixed @chiko code, you didn't pointed out that using grep and sed inside the for loop shall be avoided.
1

Here's a bash + awk solution that'll do the job efficiently:

#!/bin/bash

array=(
    "192.168.0.34 test1ip"
    "192.168.0.35 test2ip"
    "192.168.0.33 test3ip"
)

awk '
    FNR == NR {
        aarr[$2] = $1
        next
    }
    ! ($2 in aarr)
    END {
        for (host in aarr)
            print aarr[host], host
    }
' <(printf '%s\n' "${array[@]}") testing.txt
127.0.0.1 localhost
somotherrandomip testing
192.168.0.33 test3ip
192.168.0.34 test1ip
192.168.0.35 test2ip

notes:

  • bash's <( commands ) is called process-subtitution. It creates a file containing the output of commands that you can use as argument.

  • awk's FNR == NR is a condition for selecting the first file argument. In this block I create an associative array that translates a hostname to its new IP address.

  • ! ($2 in aarr) means to print the records for which the hostname is not in the translation array.

  • The END is for printing the translation array (new IPs of hostnames).

1 Comment

Thanks @Fravadona for your help and time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.