Search code examples
jsonawkgawknawk

Separating output records in AWK without a trailing separator


I have the following records:

31 Stockholm
42 Talin
34 Helsinki
24 Moscow
15 Tokyo

And I want to convert it to JSON with AWK. Using this code:

#!/usr/bin/awk
BEGIN {
    print "{";
    FS=" ";
    ORS=",\n";
    OFS=":";
};

{    
    if ( !a[city]++ && NR > 1 ) {
        key = $2;
        value = $1;
        print "\"" key "\"", value;
    }
};

END {
    ORS="\n";
    OFS=" ";
    print "\b\b}";
};

Gives me this:

{
"Stockholm":31,
"Talin":42,
"Helsinki":34,
"Moscow":24,
"Tokyo":15, <--- I don't want this comma
}

The problem is that trailing comma on the last data line. It makes the JSON output not acceptable. How can I get this output:

{
"Stockholm":31,
"Talin":42,
"Helsinki":34,
"Moscow":24,
"Tokyo":15
}

Solution

  • Mind some feedback on your posted script?

    #!/usr/bin/awk        # Just be aware that on Solaris this will be old, broken awk which you must never use
    BEGIN {
        print "{";        # On this and every other line, the trailing semi-colon is a pointless null-statement, remove all of these.
        FS=" ";           # This is setting FS to the value it already has so remove it.
        ORS=",\n";
        OFS=":";
    };
    
    {
        if ( !a[city]++ && NR > 1 ) {      # awk consists of <condition>{<action} segments so move this condition out to the condition part
                                           # also, you never populate a variable named "city" so `!a[city]++` won't behave sensibly.
            key = $2;
            value = $1;
            print "\"" key "\"", value;
        }
    };
    
    END {
        ORS="\n";                          # no need to set ORS and OFS when the script will no longer use them.
        OFS=" ";
        print "\b\b}";                     # why would you want to print a backspace???
    };
    

    so your original script should have been written as:

    #!/usr/bin/awk
    BEGIN {
        print "{"
        ORS=",\n"
        OFS=":"
    }
    
    !a[city]++ && (NR > 1) {    
        key = $2
        value = $1
        print "\"" key "\"", value
    }
    
    END {
        print "}"
    }
    

    Here's how I'd really write a script to convert your posted input to your posted output though:

    $ cat file
    31 Stockholm
    42 Talin
    34 Helsinki
    24 Moscow
    15 Tokyo
    $
    $ awk 'BEGIN{print "{"} {printf "%s\"%s\":%s",sep,$2,$1; sep=",\n"} END{print "\n}"}' file
    {
    "Stockholm":31,
    "Talin":42,
    "Helsinki":34,
    "Moscow":24,
    "Tokyo":15
    }