AWK: FS의 현장 작업과 "체인" 작업을 함께 "변경"

AWK: FS의 현장 작업과 "체인" 작업을 함께 "변경"

Wikipedia 테이블에서 정보를 검색하기 위해 MediaWiki API 페이지의 데이터를 awk구문 분석하는 스크립트를 작성 중입니다 .JSON이것은 내가 사용하고 있는 예이며 awk로 파이프되고 있습니다.

내 의도는 다음과 같습니다

  • \n텍스트 항목을 실제 개행 문자로 바꾸기
  • 일부 항목을 구분하는 단일 수직 막대 앞에 있는 일부 항목과 모든 항목을 둘러싸는 이중 대괄호를 제거합니다.
  • 모든 이중 수직 막대를 ||단일 수직 막대로 교체합니다.필드 구분 기호로 사용하려면
  • 각 줄의 시작 부분에 있는 선행 수직 막대를 제거합니다.
  • 주어진 필드를 인쇄하고 빈 줄과 선행 공백을 제거합니다.

이제 문제는 이것을 성공적으로 구현했지만 awk다른 인스턴스를 파이핑하여 매우 추악한 방식으로 구현했다는 것입니다. 이것이 내가 지금까지 얻은 것입니다:

curl -s 'https://en.wikipedia.org/w/api.php?action=parse&prop=sections&page=List_of_islands_of_Spain&section=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이 스크립트를 사용하여 기술을 개발하려고 합니다.cutawk

이제 제가 알아차린 한 가지는 출력이 변경되었음에도 불구하고 첫 번째 인스턴스에서 문자열 조작이 수행되었다는 것입니다.NR 또는 NF를 변경하지 않습니다.. 이것이 제가 겪고 있는 문제의 원인이라고 생각하지만 어떻게 해결해야 할지 모르겠습니다.

이것이 내가 알고 싶은 것입니다:

이러한 모든 작업을 단일 awk 인스턴스로 "연결"할 수 있습니까? 내부적으로 이러한 작업 사이에 "파이프라인"과 같은 것이 있습니까 awk?

응답해 주시는 모든 분들께 미리 감사드립니다.

답변1

JSON을 구문 분석하기 위해 awk를 사용하는 것의 지혜에 대해서는 논의하지 않을 것입니다(gawks JSON 라이브러리를 사용하지 않는 한). 그러나 awk 호출의 쉘 파이프라인을 변환하는 방법에 대해 논의할 것입니다.

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와 유사한 프로그래밍 언어입니다. 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&section=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

RSGNU awk를 사용하면 s에서 입력 자동 분할을 설정할 수 있으며 스크립트 내에서 s를 분할 \\n할 필요가 없다는 점은 주목할 가치가 있습니다.\\n

$ 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

관련 정보