bmoreira18
bmoreira18

Reputation: 143

Creating just one looping to make list - Shell

I want to create a .xml file with an specific config, this config needs an hostname and ip, i have created the hosts.csv to input this data being them vm-tmb-test1;127.0.0.1 on .csv file for each separator line ";" is a hostname and ip of a server, but the looping i have created print for each ip in the hosts.csv

Code Structure

#!/bin/bash

for i in $(cat /var/projects/etc/hosts.csv | cut -d\; -f1)
do
    for ips in $(cat /var/projects/etc/hosts.csv | cut -d\; -f2)
    do
        if [[ ${i} == *"jua"* ]]
        then
            sed -i '$ a <node name="'${i}'" tags="infra,jua,vm" hostname="'${ips}'" username="test"/>' /var/projects/etc/resources.xml
        elif [[ ${i} == *"tmb"* ]]
        then
            sed -i '$ a <node name="'${i}'" tags="infra,tmb,vm" hostname="'${ips}'" username="tests"/>' /var/projects/etc/resources.xml 
        fi
    done
done

Host.csv content:

vm-tmb-test1;127.0.0.1
vm-tmb-test2;127.0.0.2
vm-tmb-test3;127.0.0.3
vm-jua-test4;127.0.0.4

Desired Output:

<node name="vm-tmb-test1" tags="infra,tmb,vm" hostname="127.0.0.1" username="test"/>
<node name="vm-tmb-test2" tags="infra,tmb,vm" hostname="127.0.0.2" username="test"/>
<node name="vm-tmb-test3" tags="infra,tmb,vm" hostname="127.0.0.3" username="test"/>
<node name="vm-jua-test4" tags="infra,jua,vm" hostname="127.0.0.4" username="test"/>

Actual Code Output:

<node name="vm-tmb-test1" tags="infra,tmb,vm" hostname="127.0.0.1" username="test"/>
<node name="vm-tmb-test1" tags="infra,tmb,vm" hostname="127.0.0.2" username="test"/>
<node name="vm-tmb-test1" tags="infra,tmb,vm" hostname="127.0.0.3" username="test"/>
<node name="vm-tmb-test1" tags="infra,tmb,vm" hostname="127.0.0.4" username="test"/>
<node name="vm-tmb-test2" tags="infra,tmb,vm" hostname="127.0.0.1" username="test"/>
<node name="vm-tmb-test2" tags="infra,tmb,vm" hostname="127.0.0.2" username="test"/>
<node name="vm-tmb-test2" tags="infra,tmb,vm" hostname="127.0.0.3" username="test"/>
<node name="vm-tmb-test2" tags="infra,tmb,vm" hostname="127.0.0.4" username="test"/>

How can i fix that?

Edit 1: host.csv contains then more of 200 servers hostname and ip's it will be fed with time.

Upvotes: 0

Views: 55

Answers (3)

markp-fuso
markp-fuso

Reputation: 34324

Pushing the while loop solution into a single awk call:

awk -F";" '                              # input delimiter is ";"
           { tag="UNDEFINED" }           # default tag in case $1 does not match the following patterns
$1 ~ /jua/ { tag="jua"       }
$1 ~ /tmb/ { tag="tmb"       }

           { printf "<node name=\"%s\" tags=\"infra,%s,vm\" hostname=\"%s\" username=\"test\"/>\n", $1, tag, $2 }
' host.csv

This generates:

<node name="vm-tmb-test1" tags="infra,tmb,vm" hostname="127.0.0.1" username="test"/>
<node name="vm-tmb-test2" tags="infra,tmb,vm" hostname="127.0.0.2" username="test"/>
<node name="vm-tmb-test3" tags="infra,tmb,vm" hostname="127.0.0.3" username="test"/>
<node name="vm-jua-test4" tags="infra,jua,vm" hostname="127.0.0.4" username="test"/>

NOTES:

  • again, OP can redirect the output of the printf to the final output file (alternatively, direct the entire output of the awk call to said output file)
  • for this answer I'm assuming all output should have the same string username="test"

Upvotes: 1

markp-fuso
markp-fuso

Reputation: 34324

While faster solutions (eg, awk, sed) exist, for this answer I'm going to stick with OP's idea of using a loop ...

Sample input:

$ cat host.csv
vm-tmb-test1;127.0.0.1
vm-tmb-test2;127.0.0.2
vm-tmb-test3;127.0.0.3
vm-jua-test4;127.0.0.4

Since the sample code appears to just be appending output to a *.xml file I'm going to opt for a single while loop that generates the desired output:

while IFS=";" read -r i ips                             # use ';' as input delimiter and read values into our 2 variables 'i' and 'ips'
do
        tag='UNDEFINED'                                 # define some defaults in case 'i' does not 
        uname='UNDEFINED'                               # have a match in our case statement

        case "${i}" in                                  # pattern match 'i' to determine what strings to submit to the printf command
                *jua*)  tag='jua' ; uname='test'   ;;
                *tmb*)  tag='tmb' ; uname='tests'  ;;
        esac

        printf '<node name="%s" tags="infra,%s,vm" hostname="%s" username="%s"/>\n' "${i}" "${tag}" "${ips}" "${uname}"

done < host.csv

The above generates:

<node name="vm-tmb-test1" tags="infra,tmb,vm" hostname="127.0.0.1" username="tests"/>
<node name="vm-tmb-test2" tags="infra,tmb,vm" hostname="127.0.0.2" username="tests"/>
<node name="vm-tmb-test3" tags="infra,tmb,vm" hostname="127.0.0.3" username="tests"/>
<node name="vm-jua-test4" tags="infra,jua,vm" hostname="127.0.0.4" username="test"/>

NOTES:

  • OP can redirect the output of the printf to the final destination
  • this should be a bit more efficient than repetitive sed -i calls
  • I have copied OPs code snippet that shows the use of username="{test|tests}" (though OP's sample output only shows the string test); OP can edit the proposed code as needed

Upvotes: 1

M. Nejat Aydin
M. Nejat Aydin

Reputation: 10123

A single GNU sed call could do the job:

sed -E 's/([^-]*)-([^-]*)-([^;]*);(.*)/<node name="\1-\2-\3" tags="infra,\2,\1" hostname="\4" username="test"\/>/' file

Upvotes: 1

Related Questions