Utiliser awk et sortinger pour sortinger une table par champ ID

J’apprends Unix, et je veux sortinger cette table:

Name:Alice,ID:2368,Hometown:columbus,bithday:03/11/1988 Name:Ted,ID:2368,Hometown:Portland,bithday:06-11-1992 Name:Mark,ID:2218,Hometown:Palo Alto,bithday:04-23-1984 Name:Xiao,ID:2571,hometown:Carson,bithday:07/06/1975 Name:Rain,ID:0264,hometown:little stone,bithday:11-09-1982 Name:Susan,ID:1261,Hometown:Menlo park,bithday:12-13-1989 Name:Zack,ID:1594,Hometown:columbus,bithday:02-04-1984 

Et faites-le formaté comme ceci:

 Rain,0264,little stone,11-09-1982 Susan,1261,Menlo park,12-13-1989 Zack,1594,columbus,02-04-1984 Mark,2218,Palo Alto,04-23-1984 Alice,2368,columbus,03-11-1988 Ted,2368,Portland,06-11-1992 Xiao,2571,Carson,07-06-1975 

Je veux filtrer la clé dans les paires clé-valeur (clé: valeur), puis sortinger par ID en utilisant awk et sortinger.

Quelles commandes utiliser pour cela?

C’est aussi simple que cela:

 awk -F: '{gsub(/,[^:]*:/,",");print $2}' You_file| sort -t, -k 2,2n 

testé ci-dessous:

 > cat temp Name:Alice,ID:2368,Hometown:columbus,bithday:03/11/1988 Name:Ted,ID:2368,Hometown:Portland,bithday:06-11-1992 Name:Mark,ID:2218,Hometown:Palo Alto,bithday:04-23-1984 Name:Xiao,ID:2571,hometown:Carson,bithday:07/06/1975 Name:Rain,ID:0264,hometown:little stone,bithday:11-09-1982 Name:Susan,ID:1261,Hometown:Menlo park,bithday:12-13-1989 Name:Zack,ID:1594,Hometown:columbus,bithday:02-04-1984 > 

Maintenant l’exécution:

 > awk -F: '{gsub(/,[^:]*:/,",");print $2}' temp | sort -t, -k 2,2n Rain,0264,little stone,11-09-1982 Susan,1261,Menlo park,12-13-1989 Zack,1594,columbus,02-04-1984 Mark,2218,Palo Alto,04-23-1984 Alice,2368,columbus,03/11/1988 Ted,2368,Portland,06-11-1992 Xiao,2571,Carson,07/06/1975 

Cela m’a pris du temps à comprendre, jusqu’à ce que j’ai finalement vu que “anniversaire” était mal orthographié dans vos données d’entrée.

Vous pouvez aller avec tout cela et parsingr les données en tant que données réelles:

 awk -F, ' BEGIN { fmt="%s,%s,%s,%s\n"; } { for (i=1;i<=NF;i++) { # walk through the fields... split($i,a,":"); # split each one at the colon, save to array v[tolower(a[1])]=a[2]; # need tolower() as "Hometown" is inconsistent } split(v["bithday"],b,/[-\/]/); # regex here handles your inconsistent divider v["bithday"]=sprintf("%s-%s-%s",b[3],b[2],b[1]); printf(fmt,v["name"],v["id"],v["hometown"],v["bithday"]); } ' input.txt | sort -t, -k2 

Cela parcourt chaque ligne, décompose les champs par des virgules, stocke les combinaisons clé = valeur dans un tableau, ajuste votre format "jour" et imprime. (Notez que j'ai choisi un format de date plus sensible pour vous.)

Mais il serait peut-être plus simple de faire des correspondances simples:

 sed -Ene 's/^[[:alpha:]]+://;s/,[[:alpha:]]+:/,/g;s/([0-9]{2}).([0-9]{2}).([0-9]{4})$/\3-\2-\1/;p' input.txt \ | sort -t, -k2 

Cela produit les mêmes résultats, mais avec moins de code. Si vous avez besoin de faire des choses plus intéressantes avec vos données d'entrée, alors bien sûr, awk est la voie à suivre.

Oh, et mon sed vient de FreeBSD, il utilise donc l'option -E pour obtenir ERE. Si vous utilisez Linux ou un autre fournisseur de GNU sed, vous pouvez probablement remplacer le -E par -r .

En utilisant grep pour trouver la valeur, collez pour réassembler les lignes, et bien sûr sortingez:

 grep -oP '(?<=:).*?(,|$)' filename | paste -d "" - - - - | sort -n -t, -k2 

En supposant aucune virgule dans les valeurs.

La manière la plus simple que j’ai trouvée est d’utiliser awk pour reformater la sortie et append une nouvelle colonne que le sort utilisera et utiliser awk nouveau pour masquer cette colonne.

 $ cat test.dat Name:Alice,ID:2368,Hometown:columbus,bithday:03/11/1988 Name:Ted,ID:2368,Hometown:Portland,bithday:06-11-1992 Name:Mark,ID:2218,Hometown:Palo Alto,bithday:04-23-1984 Name:Xiao,ID:2571,hometown:Carson,bithday:07/06/1975 Name:Rain,ID:0264,hometown:little stone,bithday:11-09-1982 Name:Susan,ID:1261,Hometown:Menlo park,bithday:12-13-1989 Name:Zack,ID:1594,Hometown:columbus,bithday:02-04-1984 $ cat test.dat| awk -F, '{ gsub(/[a-zA-Z]+:/, ""); print $2,$0; }' | sort | awk '{ $1=""; print; }' Rain,0264,little stone,11-09-1982 Susan,1261,Menlo park,12-13-1989 Zack,1594,columbus,02-04-1984 Mark,2218,Palo Alto,04-23-1984 Alice,2368,columbus,03/11/1988 Ted,2368,Portland,06-11-1992 Xiao,2571,Carson,07/06/1975 

Le -F est de spécifier le délimiteur (ici , ). Nous voulons ensuite supprimer le nom de la colonne (c’est-à-dire toute lettre suivie de : , et enfin afficher la colonne ID et toute la ligne réécrite. Nous utilisons ensuite sort , qui suppose par défaut que la clé de sorting est la première colonne, et awk nouveau pour afficher uniquement la deuxième partie de chaque ligne.

Edit : étant donné les espaces dans les villes, il y avait un problème de sortie avec awk. Par souci de simplicité, je viens de réaffecter la première variable (qui est la colonne que vous voulez masquer) et d’imprimer la ligne entière.

Voici un moyen d’utiliser GNU awk :

 awk 'BEGIN { FS="[,:]"; OFS="," } { for (i=2; i<=NF; i+=2) printf (i!=NF) ? $i OFS : $i ORS | "sort -t, -nk2" }' file.txt 

Résultats:

 Rain,0264,little stone,11-09-1982 Susan,1261,Menlo park,12-13-1989 Zack,1594,columbus,02-04-1984 Mark,2218,Palo Alto,04-23-1984 Alice,2368,columbus,03/11/1988 Ted,2368,Portland,06-11-1992 Xiao,2571,Carson,07/06/1975 

Doit-il y avoir un awk? Si non:

  1. utilisez Vim pour supprimer les chaînes de clé avec :%s/[az]*://gi
  2. Utilisez sortinger pour sortinger: sort -t , -k 2 file

Si AWK est un must, alors je pense à cela , pour sortinger sans perdre les clés – mais la réponse @Aif est bien aussi.

EDIT: amélioré grâce à la regex de @Aif et grâce au commentaire de @ Ghoti. Maintenant, la commande Vim pour la substitution utilise l’expression régulière et la casse clé et le texte «pas important», comme dirait maître Yoda.

Réglez simplement le FS et l’OFS sur ce qu’ils sont dans votre tête, imprimez les champs que vous voulez et sortingez:

 $ awk -F'[:,]' -v OFS=, '{print $2,$4,$6,$8}' file | sort -t, -k2n Rain,0264,little stone,11-09-1982 Susan,1261,Menlo park,12-13-1989 Zack,1594,columbus,02-04-1984 Mark,2218,Palo Alto,04-23-1984 Alice,2368,columbus,03/11/1988 Ted,2368,Portland,06-11-1992 Xiao,2571,Carson,07/06/1975 

Après l’avoir formaté selon vos besoins (je comprends que vous en avez), vous pouvez sortinger par la deuxième colonne en canalisant les données pour sort -t, -k2 .

Si vous ne l’avez pas encore fait, je pense que l’un des moyens les plus simples serait sed 's/[[:alnum:]]*://g' .

Donc, toute la commande serait

 sed 's/[[:alnum:]]*://g' table.csv | sort -t, -k2 

cat temp.txt | awk -F “, |:” ‘{print $ 2 “,” $ 4 “,” $ 6} “| sort -t, -k2n