Comment utiliser sort sur une commande d'impression awk?


8

J'ai quelques commandes dans un script awk que j'écris:

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

Quelles sorties:

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

Comment puis-je utiliser la sortcommande dans mon script awk pour trier UNIQUEMENT les joueurs et leurs numéros?


3
Compte tenu de vos commentaires sur les réponses, vous semblez confondre awk et script shell dans votre question. Il semble que vous souhaitiez faire le tri dans votre script awk , pas dans le script shell l' invoquant. Si c'est correct, veuillez modifier votre question et remplacer les deux occurrences de «shell» par «awk». Sur une note distincte: oui, awk a une fonction de tri, mais elle est très impliquée: vous devez stocker toutes les lignes dans un tableau, saisies sur leur deuxième champ, dont vous aurez besoin d'extraire x, puis définir PROCINFO["sorted_in"]une valeur cryptique, puis sortez le tableau. Je n'irais pas là-bas.
zwets du

1
Je veux dire: je n'irais pas là-bas étant donné la simplicité de ... | sort -k2,2.
zwets

@zwets Comment pourrais-je implémenter ...| sort -k2,2s'il y a d'autres lignes à imprimer? Vérifiez la question modifiée.
KM142646

En echosaisissant la ligne d'en-tête à partir du shell, puis exécutez le awk | sortpipeline.
zwets

Réponses:


12

vous pouvez ajouter | sort -k2à votre commande. Cela triera par ordre alphabétique en fonction de la deuxième colonne.

Exemple:

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

résulte en

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

Malheureusement, j'utilise un script, et la commande sort sera mélangée avec de nombreuses autres sorties. Existe-t-il un moyen de trier la sortie de {print x, $2}directement dans le code de script? Je reçois une erreur lors de la tuyauterie if(sum[x] > 500) {print x, $2} | sort -k2.
KM142646

3
@KMoy: if(sum[x] > 500) {print x, $2}est du code Awk alors qu'il | sort -k2s'agit d'une commande shell. Évidemment, vous ne pouvez pas mélanger les deux comme ça parce que ce sont des langues différentes. Au lieu de cela, vous devez appliquer la sortcommande à la sortie de l'interpréteur Awk qui exécute votre extrait de code Awk. Si vous ne savez pas ce que je veux dire, veuillez développer votre question pour nous donner une image complète.
David Foerster

1
Vous écrivez un script shell, non? Ensuite, vous avez deux options: 1. exécuter ./my-script.sh | sort -k2. 2. ajoutez `| trier -k2` à la ligne de votre script qui produit la sortie donnée dans votre question.
Wayne_Yux

@Wayne_Yux Veuillez vérifier les modifications apportées à la question d'origine.
KM142646

Alors vous avez probablement besoin de la réponse de @steeldriver
Wayne_Yux

9

Bien que je ne le recommanderais pas (étant donné la relative simplicité de la transmission du résultat via une sortcommande externe ), vous pouvez le faire au moins avec les versions récentes de GNU awk (au moins 4.0 IIRC), comme décrit dans Trier les valeurs et les indices de tableau avec gawk

Voici comment vous pouvez l'implémenter, en supposant que vous avez les données dans un tableau associatif dans lequel se trouve l'index Firstname Lastname. Vous devez d'abord définir une fonction de comparaison personnalisée qui divise l'index, compare d'abord Lastnamepuis (comme un bris d'égalité) sur Firstnamepar exemple

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;
}

Vous pouvez maintenant utiliser la PROCINFO["sorted_in"]méthode de tri des tableaux mentionnée dans les commentaires de @zwets

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

Mettre ensemble

#!/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];
}

Essai:

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

Dans les versions antérieures ou inférieures de awk, votre meilleur pari peut être de stocker les données indexées à la Lastname Firstnameplace, de les trier avec le conventionnel asorti, puis de diviser et d'échanger les champs des index lorsque vous parcourez le tableau pour l'imprimer:

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

Pour sortuniquement par le deuxième champ séparé par des espaces, utilisez la touche -k2,2:

... | sort -k2,2

par défaut sortfait le tri lexicographiquement.

Notez que, si vous ne mentionnez pas le dernier champ pour la clé de tri, c'est-à-dire si vous utilisez simplement, -k2vous n'obtiendrez peut-être pas le résultat souhaité car cela dépendra sortde tous les champs à partir de la seconde.

Vérifiez également man sort.


Veuillez vérifier le commentaire sur le post de Wayne pour ce dont j'ai besoin
KM142646

1

Essayer

awk -f myscript.awk | sort -k2

Où myscript.awk contient des commandes purement awk.

Si votre script réel est un script shell, vous avez plusieurs options, notamment

  • Sortie du tuyau via le tri. ./myscript.bash | sort -k2
  • Réécrire le code en tant que fonction dans le script au
    lieu de

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

    Faire

    $ 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
    

Mais notez que vous pouvez également appliquer le tri à la structure do ... done au lieu de créer une fonction.

    do
       echo $i
    done | sort

Pourquoi définir la fonction?
zwets

@zwets, il facilite la transmission des résultats de code arbitraire, y compris les structures de contrôle en boucle, via un pipeline. Il y a des cas où cela n'est pas nécessaire mais je trouve que c'est un schéma général utile. Je vais modifier ma réponse pour le démontrer.
RedGrittyBrick

1

Pour trier vos données à imprimer:

  • Supposons que vous souhaitiez imprimer le deuxième champ (séparé par des espaces), utilisez ceci:

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

    par exemple:

    $cat>data.txt
    1 Kedar 20
    2 Amit 30
    3 Rahul 21
    ^C
    
    $awk '{print $2}' | sort
    Amit
    Kedar
    Rahul
    
  • Si vous souhaitez imprimer l'intégralité de votre data.txtmais trié sur la colonne 2, alors:

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

Utilisez cette logique dans vos besoins.

Vous pouvez utiliser man sortpour des fonctionnalités plus intéressantes de sort.


0

qu'en est-il ci-dessous:

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

ça marche quand j'ai testé.


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

Pour trier la sortie dans un fichier:

print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2 | "sort -k2,2 > sortedFile"}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.