Разделение выходных записей в AWK без конечного разделителя
У меня есть следующие записи:
31 Stockholm
42 Talin
34 Helsinki
24 Moscow
15 Tokyo
И я хочу преобразовать его в JSON с помощью AWK. Используя этот код:
#!/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}";
};
Дает мне это:
{
"Stockholm":31,
"Talin":42,
"Helsinki":34,
"Moscow":24,
"Tokyo":15, <--- I don't want this comma
}
Проблема в том, что запятая в последней строке данных. Это делает вывод JSON неприемлемым. Как я могу получить этот вывод:
{
"Stockholm":31,
"Talin":42,
"Helsinki":34,
"Moscow":24,
"Tokyo":15
}
4 ответа
Не могли бы вы оставить отзыв о вашем опубликованном сценарии?
#!/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???
};
поэтому ваш оригинальный сценарий должен был быть написан как:
#!/usr/bin/awk
BEGIN {
print "{"
ORS=",\n"
OFS=":"
}
!a[city]++ && (NR > 1) {
key = $2
value = $1
print "\"" key "\"", value
}
END {
print "}"
}
Вот как я на самом деле написал бы скрипт, чтобы конвертировать ваши опубликованные данные в ваши опубликованные результаты:
$ 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
}
У вас есть пара вариантов. Проще всего было бы добавить запятую предыдущей строки, когда вы собираетесь написать новую строку:
Установите переменную
first = 1
в вашемBEGIN
,Когда вы собираетесь напечатать строку, проверьте
first
, Если это1
затем просто установите его0
, Если это0
распечатайте запятую и новую строку:if (first) { first = 0; } else { print ","; }
Смысл этого в том, чтобы не ставить лишнюю запятую в начале списка.
использование
printf("%s", ...)
вместоprint ...
так что вы можете избежать новой строки при печати записи.Добавьте дополнительную новую строку перед закрывающей скобкой, как показано в:
print "\n}";
Также обратите внимание, что если вас не волнует эстетика, JSON на самом деле не требует перевода строки между элементами и т. Д. Вы можете просто вывести одну большую строку для всей энчилады.
Вы должны действительно использовать парсер JSON, но вот как с awk
:
BEGIN {
print "{"
}
NR==1{
s= "\""$2"\":"$1
next
}
{
s=s",\n\""$2"\":"$1
}
END {
printf "%s\n%s",s,"}"
}
Выходы:
{
"Stockholm":31,
"Talin":42,
"Helsinki":34,
"Moscow":24,
"Tokyo":15
}
Почему бы не использовать 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)
Это выводит:
{
"Helsinki": 34,
"Moscow": 24,
"Stockholm": 31,
"Talin": 42,
"Tokyo": 15
}