Imprime o menor inteiro do arquivo usando a função personalizada do awk?

1
A função

awk tem esta aparência em um nome de arquivo fun.awk :

{
print small()
}
function small()

{
a[NR]=$0

smal=0

for(i=1;i<=3;i++)
{
if( a[i]<a[i+1])

smal=a[i]

else

smal=a[i+1]

}
return smal
}

O conteúdo de awk.write :

1
23 
32

O comando awk é:

awk -f fun.awk awk.write

Isso não me dá nenhum resultado? Por quê?

atualização

{

print f()
}
function f()

{


if(NR==1){s=$0}


if($0<p)

{s=$0}

{p=$0}

 { return s}

}
    
por asad 08.01.2016 / 13:52

2 respostas

1

Ambas as versões do seu código executarão a função small em todas as linhas do arquivo de entrada. Se você quiser encontrar o menor número no arquivo inteiro, precisará executar a função apenas uma vez e no final, depois que o arquivo inteiro tiver sido processado. Sua função atualizada parece estar funcionando e imprimindo a saída correta três vezes, mas isso ocorre apenas porque o menor número está na primeira linha. Se você executá-lo neste arquivo:

$ cat awk.write
10
9
8

Você receberá esta saída:

awk -f fun.awk awk.write
10
9
8

Isso ocorre porque, toda vez que a função é executada, o número da linha atual é menor do que o que foi salvo, portanto, ela é impressa. Você precisa usar um bloco END{} e executar a função lá:

function small(){
    for(i=1;i<=NR;i++)
    {
      ## If smal is not set or if it is greater than a[i]
      if(smal=="" || a[i]<=smal)
        smal=a[i]
    }
return smal
}
{
    ## NR is the current line number. This saves the current line
    ## in the array a.
    a[NR]=$0
}
## This will be executed only after everything has been read
END{
    print small()
}

Também generalizei para usar NR em vez de 3 , para que ele possa funcionar em qualquer número de linhas. Você poderia simplificar ainda mais para apenas:

{
    if(small=="" || $0<small){
    small=$0
    }
}
END{print small}

Qual é o mesmo que este one-liner:

awk '(small=="" || $0<small){small=$0}END{print small}' awk.write   
    
por 08.01.2016 / 20:18
1

A sintaxe da cláusula if está errada, use:

if( a[i]<a[i+1]){
  smal=a[i]
}else{
  smal=a[i+1]
}

Mas, imprimirá o valor para cada linha.

Uma solução melhor para o seu problema seria:

sort -n file | head -1
  • Isso classifica o conteúdo do arquivo numericamente ascendente e head imprime apenas a primeira linha.

Ou se deve ser awk :

awk 'NR==1{s=$0} $0<p{s=$0} {p=$0} END{print s}' file
  • NR==1{s=$0} se for a primeira linha, defina a variável s .
  • $0<p{s=$0} se a linha atual for menor que a anterior, defina a variável s para esse valor.
  • {p=$0} para cada linha, defina a variável p (anterior) para a próxima iteração.
  • END{print s} quando todas as linhas são processadas, imprima o valor de s .

Editar: tudo o que em uma função ficaria:

awk 'function f(){ if(NR==1){s=$0} if($0<p){s=$0}p=$0} {f()} END{print s}' file
    
por 08.01.2016 / 14:07