Como usar a classificação em um comando awk print?


8

Eu tenho alguns comandos em um script awk que estou escrevendo:

print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2}

Quais saídas:

Here are some players and their numbers, sorted by last name
Lebron James 23
Kevin Durant 35
Kobe Bryant 24
Blake Griffin 32
Dikembe Mutumbo 55

Como posso usar o sortcomando no meu script awk para classificar os jogadores e seus números SOMENTE?


3
Dado seus comentários sobre as respostas, você parece estar confundindo o awk e o shell script na sua pergunta. Parece que você deseja fazer a classificação no seu script awk , não no script shell que o invoca. Se estiver correto, edite sua pergunta e substitua as duas ocorrências de 'shell' por 'awk'. Em uma nota separada: sim, o awk tem um recurso de classificação, mas está bastante envolvido: você deve armazenar todas as linhas em uma matriz digitada no segundo campo, das quais você precisará extrair xe definir PROCINFO["sorted_in"]um valor criptográfico, em seguida, imprima a matriz. Eu não iria lá.
Zwets

1
Quero dizer: eu não iria lá, dada a simplicidade de ... | sort -k2,2.
Zwets

@zwets Como eu implementaria ...| sort -k2,2se houver outras linhas que precisam ser impressas? Verifique a pergunta editada.
precisa saber é o seguinte

Ao echopressionar a linha de cabeçalho do shell, execute o awk | sortpipeline.
zwets

Respostas:


12

você pode adicionar | sort -k2ao seu comando. Isso será ordenado alfabeticamente com base na segunda coluna.

Exemplo:

$ echo "Lebron James 23
Kevin Durant 35
Kobe Bryant 24
Blake Griffin 32
Dikembe Mutumbo 55" | sort -k2

resulta em

Kobe Bryant 24
Kevin Durant 35
Blake Griffin 32
Lebron James 23
Dikembe Mutumbo 55

Infelizmente, estou usando um script, e o comando de classificação será misturado com muitas outras saídas. Existe uma maneira de classificar a saída {print x, $2}diretamente no código do script? Estou recebendo um erro ao canalizar if(sum[x] > 500) {print x, $2} | sort -k2.
KM142646 #

3
@KMoy: if(sum[x] > 500) {print x, $2}é o código Awk enquanto | sort -k2é um comando do shell. Obviamente, você não pode misturar os dois assim porque são idiomas diferentes. Em vez disso, você precisa aplicar o sortcomando à saída do intérprete do Awk que executa seu snippet de código do Awk. Se você não sabe o que quero dizer, expanda sua pergunta para nos dar uma visão completa.
David Foerster

1
Você está escrevendo um script de shell, certo? Então você tem duas opções: 1. execute ./my-script.sh | sort -k2. 2. adicione `| ordene -k2 na linha do seu script que produz a saída fornecida na sua pergunta.
Wayne_Yux

@Wayne_Yux Verifique as edições feitas na pergunta original.
KM142646

Então você provavelmente terá a resposta de @steeldriver
Wayne_Yux

9

Embora eu não o recomende (dada a relativa simplicidade de canalizar o resultado através de um sortcomando externo ), você pode fazer isso pelo menos com versões recentes do GNU awk (pelo menos 4.0 IIRC), conforme descrito em Classificando valores e índices de matrizes com gawk

Veja como você pode implementá-lo, supondo que você tenha os dados em uma matriz associativa na qual o índice está Firstname Lastname. Primeiro, você precisa definir uma função de comparação personalizada que divida o índice e depois comparar primeiro Lastname(como desempate) emFirstname exemplo

function mycmp(ia, va, ib, vb, sa, sb) {
  if(split(toupper(ia), sa) && split(toupper(ib), sb)) {
    if(sa[2] < sb[2]) return -1;
    else if (sa[2] > sb[2]) return 1;
    else {
      # compare first names
      if(sa[1] < sb[1]) return -1;
      else if (sa[1] > sb[1]) return 1;
      else return 0;
    }
  }
  else return 0;
}

Agora você pode usar o PROCINFO["sorted_in"]método de classificação de matriz mencionado nos comentários por @zwets

PROCINFO["sorted_in"] = "mycmp";
for(i in a) print i, a[i];

Juntar as peças

#!/usr/bin/gawk -f

function mycmp(ia, va, ib, vb, sa, sb) {
  if(split(toupper(ia), sa) && split(toupper(ib), sb)) {
    if(sa[2] < sb[2]) return -1;
    else if (sa[2] > sb[2]) return 1;
    else {
      # compare first names
      if(sa[1] < sb[1]) return -1;
      else if (sa[1] > sb[1]) return 1;
      else return 0;
    }
  }
  else return 0;
}

{
  a[$1" "$2] = $3;
}

END {
  PROCINFO["sorted_in"] = "mycmp";
  for(i in a) print i, a[i];
}

Teste:

$ ./namesort.awk yourfile
Kobe Bryant 24
Kevin Durant 35
Blake Griffin 32
Lebron James 23
Dikembe Mutumbo 55

Nas versões menor ou mais antiga do awk, sua melhor aposta pode ser armazenar os dados indexados Lastname Firstname, classificar com o convencional asorti, dividir e trocar os campos dos índices à medida que você percorre a matriz para imprimi-la:

awk '
  {a[$2" "$1]=$3} 
  END {
    n=asorti(a,b); for (i=1;i<=n;i++) {split(b[i],s); print s[2], s[1], a[b[i]]}
}' yourfile

5

Para sortapenas pelo segundo campo separado por espaço em branco, use a chave -k2,2:

... | sort -k2,2

por padrão, sortfaz a classificação lexicograficamente.

Observe que, se você não mencionar o último campo da chave de classificação, ou seja, se você apenas o usar -k2, poderá não obter o resultado desejado, pois isso ocorrerá de sortacordo com todos os campos a partir do segundo.

Verifique também man sort.


Por favor, verifique o comentário no post de Wayne para o que eu preciso #
KM142646 1/16

1

Tentar

awk -f myscript.awk | sort -k2

Onde myscript.awk contém comandos puramente awk.

Se o seu script atual for um shell, você terá várias opções, incluindo

  • Saída do tubo através da classificação. ./myscript.bash | sort -k2
  • Reescreva o código como uma função dentro do script
    Em vez de

    $ cat t1
    #!/bin/bash
    for i in 2 4 3 1 5;
    do
      echo $i
    done
    
    $ ./t1
    2
    4
    3
    1
    5
    

    Faz

    $ cat t2
    #!/bin/bash
    function foo {
      for i in 2 4 3 1 5;
      do
        echo $i
      done
    }
    foo | sort
    
    $ ./t2
    1
    2
    3
    4
    5
    

Mas note que você também pode aplicar a classificação à estrutura do ... done em vez de criar uma função.

    do
       echo $i
    done | sort

Por que definir a função?
Zwets

@zwets, facilita a alimentação dos resultados de código arbitrário, incluindo estruturas de controle em loop, através de um pipeline. Há casos em que é desnecessário, mas acho um padrão geral útil. Vou editar minha resposta para demonstrar isso.
RedGrittyBrick #

1

Para classificar seus dados para impressão:

  • Suponha que você queira imprimir o 2º campo (separado por espaço em branco) use isto:

    awk '{print $2}' data.txt | sort
    

    por exemplo:

    $cat>data.txt
    1 Kedar 20
    2 Amit 30
    3 Rahul 21
    ^C
    
    $awk '{print $2}' | sort
    Amit
    Kedar
    Rahul
    
  • Se você deseja imprimir o seu todo, data.txtmas classificado na coluna 2, então:

    $awk '{print}'|sort -k2
    2 Amit 30
    1 Kedar 20
    3 Rahul 21
    

Use esta lógica (s) em sua exigência.

Você pode usar man sortpara recursos mais interessantes de sort.


0

o que dizer abaixo:

 awk 'BEGIN{str="1\n2\n3\n4"; system("echo -e \""str"\" | sort -r")}'

funciona quando eu testei.


0
print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2 | "sort -k2,2"}

Para classificar a saída em um arquivo:

print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2 | "sort -k2,2 > sortedFile"}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.