Tentando converter um programa C simples em um programa AWK

2
Hey guys há algumas semanas atrás eu escrevi um programa C que solicita ao usuário o nome de um arquivo de texto e, em seguida, solicita ao usuário uma palavra. Em seguida, o programa envia o arquivo de texto de entrada com números à esquerda do texto e exibe o número de vezes que a palavra aparece no arquivo de texto. Também mostra os números de linha correspondentes nos quais as palavras estão localizadas.

Aqui está uma amostra dele em ação:

Enter the name of a text file: bond.txt

Enter the pattern to search for: Bond

File contents:

1) Secret agent Bond had been warned not to tangle with Goldfinger.

2) But the super-criminal's latest obsession was too strong, too dangerous.

3) He had to be stopped.

4) Goldfinger was determined to take possession of half the supply of

5) mined gold in the world--to rob Fort Knox!

6) For this incredible venture he had enlisted the aid of the top

7) criminals in the U.S.A, including a bevy of beautiful thieves from the

8) Bronx. And it would take all of Bond's unique talents to make it fail--

9) as fail it must.

There is a match on line 1

There is a match on line 8

'Bond' appeared 2 times in the file bond.txt.

Atualmente, estou tentando praticar a programação do awk, repetindo o programa que fiz em C, mas usando o awk.

Aqui está o que eu posso levantar até agora:

BEGIN{
    printf("Enter filename : ")
    getline file < "-"
    while((getline < file)) {
        {print "File Contents:"}
        {printf("%5d) %s\n", NR,$0)}
    }
}

Qual seria a melhor e mais eficiente maneira de me permitir analisar o arquivo de texto linha por linha para procurar a palavra digitada pelo usuário ?. Alguma dica, truques? Obrigado.

    
por Blade. T 18.11.2015 / 18:20

2 respostas

2
$ awk '/Bond/{c++; print "There is a match on line " NR} END{print "\"Bond\" appeared " c " times in the file " FILENAME}' bond.txt
There is a match on line 1
There is a match on line 8
"Bond" appeared 2 times in the file bond.txt

Como funciona

O awk implicitamente percorre todas as linhas de entrada.

  • /Bond/{c++; print "There is a match on line " NR}

    Para linhas que correspondem à regex Bond , o contador c é incrementado e uma mensagem é impressa mostrando em qual linha a correspondência está ativada. No awk, o número de linhas lidas até agora é NR .

  • END{print "\"Bond\" appeared " c " times in the file " FILENAME}

    Após a última linha ser lida, uma mensagem é impressa mostrando o número total de correspondências.

Versão de várias linhas

Para quem gosta do código espalhado por várias linhas:

awk '

/Bond/{
    c++
    print "There is a match on line " NR
}

END{
    print "\"Bond\" appeared " c " times in the file " FILENAME
}
' bond.txt

Exibindo o conteúdo do arquivo antes do resumo do arquivo

Esta abordagem lê o arquivo duas vezes. Na primeira vez, imprime a versão do arquivo formatado com números de linha. A segunda vez que imprime a saída de resumo:

$ awk 'FNR==NR{printf("%5d) %s\n", NR,$0);next} /Bond/{c++; print "There is a match on line " FNR} END{print "\"Bond\" appeared " c " times in the file " FILENAME}' bond.txt{,}
    1) Secret agent Bond had been warned not to tangle with Goldfinger.
    2) But the super-criminal's latest obsession was too strong, too dangerous.
    3) He had to be stopped.
    4) Goldfinger was determined to take possession of half the supply of
    5) mined gold in the world--to rob Fort Knox!
    6) For this incredible venture he had enlisted the aid of the top
    7) criminals in the U.S.A, including a bevy of beautiful thieves from the
    8) Bronx. And it would take all of Bond's unique talents to make it fail--
    9) as fail it must.
There is a match on line 1
There is a match on line 8
"Bond" appeared 2 times in the file bond.txt

O acima difere da primeira versão de duas maneiras. Primeiro, o arquivo é fornecido na linha de comando duas vezes como bond.txt bond.txt ou, usando um truque de expansão de chave brace , como bond.txt{,} .

Em segundo lugar, adicionamos o comando:

FNR==NR{printf("%5d) %s\n", NR,$0);next}

Este comando só é executado se FNR==NR onde NR é o total do número de linhas lidas até agora e FNR é o número de linhas lidas do arquivo atual. Então, quando FNR==NR , estamos lendo o arquivo pela primeira vez. Em seguida, printf da saída formatada e pula para a linha next , ignorando o restante dos comandos no script.

Alternativa

Nesta versão, lemos o arquivo apenas uma vez, imprimindo a versão formatada enquanto salvamos as informações de resumo a serem impressas no final:

$ awk '{printf("%5d) %s\n", NR,$0)} /Bond/{c++; s=s ORS "There is a match on line " FNR} END{print s; print "\"Bond\" appeared " c " times in the file " FILENAME}' bond.txt
    1) Secret agent Bond had been warned not to tangle with Goldfinger.
    2) But the super-criminal's latest obsession was too strong, too dangerous.
    3) He had to be stopped.
    4) Goldfinger was determined to take possession of half the supply of
    5) mined gold in the world--to rob Fort Knox!
    6) For this incredible venture he had enlisted the aid of the top
    7) criminals in the U.S.A, including a bevy of beautiful thieves from the
    8) Bronx. And it would take all of Bond's unique talents to make it fail--
    9) as fail it must.

There is a match on line 1
There is a match on line 8
"Bond" appeared 2 times in the file bond.txt
    
por 18.11.2015 / 19:12
0

O seguinte deve duplicar a função do seu código c de amostra:

#!/bin/awk -f
BEGIN{
    printf("Enter the name of a text file: ")
    getline file < "-"
    printf("Enter the pattern to search for: ")
    getline searchfor < "-"
    print "File contents:"
    while (getline < file){
        # NR does not work for files read with getline in this way, so....
        linenum++
        printf("%5d) %s\n",linenum,$0)
        if ($0 ~ searchfor){
            matchcount++
            matches=matches sprintf("There is a match on line %d\n",linenum)
        }
    }
    print matches
    printf("'%s' appeared %d times in file %s.\n",searchfor,matchcount,file)
}
    
por 18.11.2015 / 23:57