I have a file with Server and Domain names in it as below.

Names.txt :

ABCDomain ContractABCServer_1
ABCDomain ABC_server1
LinkDomain CoreLinkServer_1
TADDomain TADServer_1

(I'm getting above file after performing sort and unique operations to some other file.)---just additional info

I need to extract values from above file and pass it to a xyz command (the command is used to restart servers) as a parameter in below format.



I m using below stated logic, but it doesn't give me the desired output as the DomainName has to come just once for each set. Also I m having trouble in keeping the same line.



IFS=' '
while read line
        DOMAIN=$(echo "$line" | awk -F " " '{print $1}')

        for word in $line
                if [[ "$word" == "$DOMAIN" ]]; then
                        Server=$(echo "$line" | awk -F " " '{print $2}' )
                        echo -n "(server:$ServerName"


done < Names.txt

4 Answers 4

    if (dom[$1]) 

    for (d in dom)
        if (d)
            print ("\""d"(server:"dom[d]")""\"")

This is quick and dirty awk solution. Save it like something.awk, then run:

awk -f something.awk Names.txt 

A quick fix in reply to your comment:

{ dom[$1]=dom[$1] ? dom[$1]",server:"$2 : "server:"$2 }

    for (d in dom)
        if (d) {
            out && out = out","
            out = out"\""d"("dom[d]")""\""
        print out
  • I used it and it has worked perfectly well. But there is a little change in the required o/p as below. "ABCDomain(server:ContractABCServer_1,server:ABC_server1)" I need "server" string before every server, not just at the beginning. Sorry for the previous typo. Hope it's possible Jun 21, 2018 at 10:03
  • Can it be done. Jun 26, 2018 at 12:13

You can assemble the comma-separated strings directly in awk and print the composite at the end:

  $1 == "ABCDomain"  {d = (d == "") ? $2 : d "," $2; next} 
  $1 == "LinkDomain" {l = (l == "") ? $2 : l "," $2; next} 
  $1 == "TADDomain"  {t = (t == "") ? $2 : t "," $2; next} 

  END {
    printf("\"ABCDomain(server:%s)\",\"LinkDomain(server:%s)\",\"TADDomain(%s)\"\n", d, l, t)


$ awk '
  $1 == "ABCDomain"  {d = (d == "") ? $2 : d "," $2; next} 
  $1 == "LinkDomain" {l = (l == "") ? $2 : l "," $2; next} 
  $1 == "TADDomain"  {t = (t == "") ? $2 : t "," $2; next} 

  END {
    printf("\"ABCDomain(server:%s)\",\"LinkDomain(server:%s)\",\"TADDomain(%s)\"\n", d, l, t)
  }' Names.txt

You can use this code, please read the code before executing it as it is creating a directory in /tmp folder named domains and then removing it the end


    IFS=' '
    declare -A domain
    mkdir /tmp/domains
    while read line
            DOMAIN=$(echo $line | awk  '{print $1}')
            SERVER=$(echo $line | awk '{print $2}' )
            echo "$SERVER," >> /tmp/domains/$DOMAIN
    done < Names.txt

    sed -ir "$ s/.,$//" /tmp/domains/*

    for i in "${!domain[@]}"; do
             echo -n "$i(server:";
             while read line ; do
                 echo -n "$line" ;
             done < /tmp/domains/$i
             echo ")"
    rm -rf /tmp/domains

This is creating a folder in /tmp folder with the following data, such that each Domain file name has a list of Servers contained in them

$ ls -lhtr /tmp/domains/
total 12K
-rw-rw-r-- 1 arushirai arushirai 11 Jun 19 17:54 TADDomain
-rw-rw-r-- 1 arushirai arushirai 16 Jun 19 17:54 LinkDomain
-rw-rw-r-- 1 arushirai arushirai 32 Jun 19 17:54 ABCDomain

$ cat /tmp/domains/ABCDomain 
$ cat /tmp/domains/LinkDomain 
$ cat /tmp/domains/TADDomain 

(Updated to correct the output format)

Using awk:

BEGIN { OFS = "," }

{ servers[$1] = (servers[$1] == "" ? "server:" $2 : servers[$1] "," "server:" $2 ) }

    $0 = ""
    for (domain in servers)
        $(++n) = sprintf("\"%s(%s)\"", domain, servers[domain])


This would add the servers as a comma-delimited string to the specific domain in the main block while parsing the input file. This is done by modifying the servers array which holds the servers for a particular domain (the domain is the key in the array).

In the END block, we loop over all keys/domains in the servers array and create an output record in the specified format.

Running this on the supplied data:

$ awk -f script.awk names.txt

A mostly equivalent bash script (requires bash 4.3+ for the associative array):

declare -A servers

while read domain server; do
done <names.txt

for domain in "${!servers[@]}"; do

printf '%s\n' "$out"

... but see "Why is using a shell loop to process text considered bad practice?".

  • Thanks. About the artice "Why is using a shell loop....." I read it, but I m still learning to use text processing basics. Jun 27, 2018 at 9:03
  • How can we neglect the single quotes that appear while accessing a variable using "$". Is there any other way of calling a variable that doesn't give single quotes. Jun 27, 2018 at 12:20
  • @AdityaTelang I'm not quite of which single quotes you refer to.
    – Kusalananda
    Jun 27, 2018 at 12:28
  • Let's say I have a command xyz.sh and I have stored the value of awk -f script.awk names.txt in a variable called PARAM. Now I run the command in script like below:- xyz.sh -domains $PARAM Here the $PARAM is resolving into --> '"TADDomain(server:TADServer_1)"' instead of "TADDomain(server:TADServer_1)" Extra quotes are comming at end and begginning which is corrupting the command. Jun 27, 2018 at 12:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.