我正在编写一个脚本,用于awk
解析JSON
MediaWiki API 页面中的数据,以便从 Wikipedia 表中检索信息。这是我正在使用的示例,它正在通过管道传输到 awk 中。
我的意图是:
\n
用实际的换行符替换出现的文本- 删除包围某些条目的双方括号,以及分隔某些条目的单个竖线之前的所有内容
- 将所有双竖线替换
||
为单竖线,以便将其用作字段分隔符 - 删除每行开头的前导竖线
- 打印给定字段,删除空行和前导空格
现在,问题是:我已经成功地实现了这一点,但是通过管道不同的awk
实例,以这种非常丑陋的方式。这是我到目前为止所得到的:
curl -s 'https://en.wikipedia.org/w/api.php?action=parse&prop=sections&page=List_of_islands_of_Spain§ion=1&prop=wikitext&format=json' |\
awk 'BEGIN { FS = "|" }\
gsub (/\\n/, "\n") gsub (/\[\[[^\|]*\||\]\]/, "")\
gsub (/\|\|/, "|")' |\ # Sub. "\n" for line-break, remove "[[" and "]]", substitute "||" for "|"
awk 'gsub (/^\|/, "")' |\ # Remove leading "|"
awk 'BEGIN { FS = "|" } {print $5}' |\ # Print 5th field
awk '{gsub (/^[ \t]*/, "")} NF' # Remove any leading whitespace and delete empty lines
我知道我可以在最后三个实例中使用sed
and ,但我正在尝试使用这个脚本来发展我的技能。cut
awk
现在,我最终注意到的一件事是,在第一个实例中完成的字符串操作,即使它改变了输出,不改变 NR 或 NF。我想这是我遇到的问题的根源,但我不知道如何解决它。
这就是我想知道的:
你能(以及我如何)将所有这些操作“链接”到一个 awk 实例中吗?内部这些操作之间的类似“管道”之类的东西awk
?
预先感谢所有回复的人。
答案1
我不会讨论使用 awk 解析 JSON 的智慧(除非您使用 gawks JSON 库),但我将讨论如何转换 awk 调用的 shell 管道:
awk 'BEGIN { FS = "|" }\
gsub (/\\n/, "\n") gsub (/\[\[[^\|]*\||\]\]/, "")\
gsub (/\|\|/, "|")' |\ # Sub. "\n" for line-break, remove "[[" and "]]", substitute "||" for "|"
awk 'gsub (/^\|/, "")' |\ # Remove leading "|"
awk 'BEGIN { FS = "|" } {print $5}' |\ # Print 5th field
awk '{gsub (/^[ \t]*/, "")} NF' # Remove any leading whitespace and delete empty lines
到单个 awk 命令中。
awk 是一种类似 C 的编程语言,它在语法或语义上与 shell 不同。您不会考虑如何在 C 程序中通过管道相互传输 C 语句,同样,您也不会在 awk 程序中这样做。
尝试这个:
$ cat tst.awk
BEGIN { FS = "|" }
{
gsub(/(\[\[[^|]*\|)|(]])/, "")
gsub(/\|\|/, FS)
split($0,lines,/\\n/)
for (i=1; i in lines; i++) {
$0 = lines[i]
sub(/^[[:space:]]+/, "", $6)
if ( $6 !~ /^$/ ) {
print $6
}
}
}
curl -s 'https://en.wikipedia.org/w/api.php?action=parse&prop=sections&page=List_of_islands_of_Spain§ion=1&prop=wikitext&format=json' |
awk -f tst.awk
Province
Isla de \u00cdzaro
Garraitz
Santa Clara
Aqueche
Txatxarramendi
Villano
Montehano
Santa Marina o Los Jorganes
Pedrosa
Virgen del Mar
Castril, Am\u00edo o M\u00edo, Las Lastras de Pech\u00f3n
La Pasiega o Solita
La Torre
Ratones o Marnay
Neptuno Ni\u00f1o
Ori\u00f1\u00f3n
Castro
Cuarezo
Llera
\u00c1guila
Suaces
Garfanta
Deva
Pantorgas
Isla Herbosa
Isla del Carmen
Illa de Arousa
Ons
La Toja Peque\u00f1a
Ansar\u00f3n
Guidoiro Areoso
A Creba
Lobeiras
Centoleiras
Beiro
Farall\u00f3ns
Guidoiro Pedregoso
Malveiras
Isla de Santa Cruz
Isla Herbosa
San Clemente
San Vicente
San Ant\u00f3n (Pontevedra)
San Ant\u00f3n (La Coru\u00f1a)
Pancha
Gavoteira
Isla de Santa Catalina
Isla Canela
Isla de Salt\u00e9s
Las Palomas
Trocadero
Sancti Petri
San Andr\u00e9s
Terreros
Isla Negra
Albor\u00e1n
San Sebasti\u00e1n
Piedra del Hombre
Isla Mayor
Rondella
Las Palomas
Isla de Tabarca
Benidorm
Portichol
Descubridor
Medas
Port Lligat
Encalladora
Cabrera
Isla del Rey
值得注意的是,使用 GNU awk,您可以设置自动RS
分隔 s 处的输入\\n
,然后您不需要\\n
在脚本内拆分 s :
$ printf 'foo\\\\nbar\n'
foo\\nbar
$ printf 'foo\\\\nbar\n' | awk '{split($0,lines,/\\\\n/); for (i=1; i in lines; i++) print i, lines[i]}'
1 foo
2 bar
$ printf 'foo\\\\nbar\n' | awk 'BEGIN{RS="[\\\\]{2}n|\n"} {print NR, $0}'
1 foo
2 bar