在AWK中分离输出记录而不使用尾随分隔符

时间:2021-06-21 16:04:15

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:

我想用AWK将它转换为JSON。使用此代码:

#!/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:

问题是在最后一条数据行上尾随逗号。它使JSON输出不可接受。我怎样才能得到这个输出:

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

4 个解决方案

#1


9  

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
}

#2


2  

You have a couple of choices. An easy one would be to add the comma of the previous line as you are about to write out a new line:

你有几个选择。当您要写出新行时,一个简单的方法是添加上一行的逗号:

  • Set a variable first = 1 in your BEGIN.

    在BEGIN中设置变量first = 1。

  • When about to print a line, check first. If it is 1, then just set it to 0. If it is 0 print out a comma and a newline:

    当要打印一行时,请先检查。如果为1,则将其设置为0.如果为0,则打印出逗号和换行符:

    if (first) { first = 0; } else { print ","; }
    

    The point of this is to avoid putting an extra comma at the start of the list.

    这一点是为了避免在列表的开头添加额外的逗号。

  • Use printf("%s", ...) instead of print ... so that you can avoid the newline when printing a record.

    使用printf(“%s”,...)代替打印...这样可以在打印记录时避免换行。

  • Add an extra newline before the close brace, as in: print "\n}";

    在闭括号前添加一个额外的换行符,如:print“\ n}”;

Also, note that if you don't care about the aesthetics, JSON doesn't really require newlines between items, etc. You could just output one big line for the whole enchilada.

另外,请注意,如果你不关心美学,JSON并不需要项目之间的换行等。你可以为整个辣酱玉米饼馅输出一个大线。

#3


1  

You should really use a json parser but here is how with awk:

你应该真的使用json解析器,但这是如何使用awk:

BEGIN {
    print "{"    
}
NR==1{
    s= "\""$2"\":"$1
    next
}
{
    s=s",\n\""$2"\":"$1
}
END {
    printf "%s\n%s",s,"}"
}

Outputs:

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

#4


0  

Why not use json parser? Don't force awk to do something isn't wasn't designed to do. Here is a solution using python:

为什么不使用json解析器?不要强迫awk做某事不是不是设计做的。这是一个使用python的解决方案:

import json

d = {}
with open("file") as f:
    for line in f:
       (val, key) = line.split()
       d[key] = int(val)

print json.dumps(d,indent=0)

This outputs:

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

#1


9  

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
}

#2


2  

You have a couple of choices. An easy one would be to add the comma of the previous line as you are about to write out a new line:

你有几个选择。当您要写出新行时,一个简单的方法是添加上一行的逗号:

  • Set a variable first = 1 in your BEGIN.

    在BEGIN中设置变量first = 1。

  • When about to print a line, check first. If it is 1, then just set it to 0. If it is 0 print out a comma and a newline:

    当要打印一行时,请先检查。如果为1,则将其设置为0.如果为0,则打印出逗号和换行符:

    if (first) { first = 0; } else { print ","; }
    

    The point of this is to avoid putting an extra comma at the start of the list.

    这一点是为了避免在列表的开头添加额外的逗号。

  • Use printf("%s", ...) instead of print ... so that you can avoid the newline when printing a record.

    使用printf(“%s”,...)代替打印...这样可以在打印记录时避免换行。

  • Add an extra newline before the close brace, as in: print "\n}";

    在闭括号前添加一个额外的换行符,如:print“\ n}”;

Also, note that if you don't care about the aesthetics, JSON doesn't really require newlines between items, etc. You could just output one big line for the whole enchilada.

另外,请注意,如果你不关心美学,JSON并不需要项目之间的换行等。你可以为整个辣酱玉米饼馅输出一个大线。

#3


1  

You should really use a json parser but here is how with awk:

你应该真的使用json解析器,但这是如何使用awk:

BEGIN {
    print "{"    
}
NR==1{
    s= "\""$2"\":"$1
    next
}
{
    s=s",\n\""$2"\":"$1
}
END {
    printf "%s\n%s",s,"}"
}

Outputs:

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

#4


0  

Why not use json parser? Don't force awk to do something isn't wasn't designed to do. Here is a solution using python:

为什么不使用json解析器?不要强迫awk做某事不是不是设计做的。这是一个使用python的解决方案:

import json

d = {}
with open("file") as f:
    for line in f:
       (val, key) = line.split()
       d[key] = int(val)

print json.dumps(d,indent=0)

This outputs:

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