Parar de processar linha única no awk após uma partida bem sucedida?

3

Existe uma maneira de parar o processamento de uma única linha no awk? Existe algo como break ou continue que funciona em pares de ação padrão em vez de estruturas de controle em uma ação?

Suponha que eu tenha o seguinte arquivo input.txt e eu estou tentando substituir cada um dos nomes com x0 , x1 , x2 , ... . No entanto, quero deixar linhas que começam com um espaço ou - sozinho.

-- data
bob     4
joe     5
bob     6
joe     7

torna-se:

-- data
x0 4
x1 5
x0 6
x1 7

E eu tenho o seguinte script que faz isso. (Como uma nota lateral, há provavelmente uma maneira melhor de estruturar isso usando um heredoc em vez de um literal de string massivo).

#!/bin/sh
awk '
    BEGIN { c = 0; }

    # do not process lines beginning with - or space
    /^[- ]/ {
        print;
    }

    # update 
    /^[^- ]/ {
        if (! ($1 in name) ) {
            new_name = "x" c;
            c += 1;
            name[$1] = new_name;
        }
        $1 = name[$1];
        print;
    }
' input.txt

Este script deixa um pouco a desejar. Em primeiro lugar, sabemos que /^[- ]/ e /^[^- ]/ são mutuamente exclusivos, mas essa propriedade não é aplicada em nenhum lugar. Gostaria de poder usar algo como break para abandonar o processamento da linha após o primeiro jogo.

/^[- ]/ {
    print;
    break;
}

Eu gostaria de poder adicionar outra cláusula para alertar o usuário sobre um problema se houver uma linha não vazia que não corresponda a nenhum dos dois primeiros padrões.

/./ {
    print "non-empty line!" > "/dev/stderr"
    # or print "non-empty line!" > "/dev/tty" if portability is a concern
}

No entanto, se eu adicionar este par de ação padrão ao script, ele será acionado após cada linha não vazia.

Existe algo que eu possa adicionar depois dos dois primeiros casos de teste para parar o processamento da linha, uma vez que ela foi "tratada com sucesso"? Se isso não for possível, existe um idioma comum para um caso geral?

    
por Gregory Nisbet 20.03.2017 / 01:47

1 resposta

2

Você pode usar o awk statement next para continuar imediatamente com o processamento do próximo registro de entrada.

Veja uma implementação alternativa do seu script awk :

awk '/^[- ] { print; next } !n[$1] { n[$1] = sprintf("x%d", c++) } { $1 = n[$1]; print }' data.in

O script é

/^[- ]/ { print; next }
!n[$1]  { n[$1] = sprintf("x%d", c++) }
        { $1 = n[$1]; print }

c é o contador. Será zero desde o início.

n é o array associativo que contém os novos rótulos / nomes. É indexado com os dados do primeiro campo / coluna do arquivo.

!n[$1] será verdadeiro se os dados no primeiro campo ainda não tiverem atribuído um novo rótulo / nome.

    
por 20.03.2017 / 09:16

Tags