Tri d'un fichier délimité par des tabulations

181

J'ai une donnée au format suivant:

foo<tab>1.00<space>1.33<space>2.00<tab>3

Maintenant, j'ai essayé de trier le fichier en fonction du dernier champ de manière décroissante. J'ai essayé les commandes suivantes mais elles n'ont pas été triées comme prévu.

$ sort -k3nr file.txt  # apparently this sort by space as delimiter

$ sort -t"\t" -k3nr file.txt
  sort: multi-character tab `\\t'

$ sort -t "`/bin/echo '\t'`" -k3,3nr file.txt
  sort: multi-character tab `\\t'

Quelle est la bonne façon de procéder?

Voici les exemples de données .

Neversaint
la source

Réponses:

318

En utilisant bash , cela fera l'affaire:

$ sort -t$'\t' -k3 -nr file.txt

Notez le signe dollar devant la chaîne entre guillemets simples. Vous pouvez en savoir plus dans les sections ANSI-C Quoting de la page de manuel bash .

Lars Haugseth
la source
2
Utilisez '"'"' pour l'utiliser dans un alias.
Pablo Bianchi
pouvez-vous montrer comment passer ce délimiteur pour trier dans une commande awk? comme dans awk '{print $0 | "sort -nr" > "outfile" }' datafile, sauf avec un séparateur de tabulation échappé envoyé à la commande sort.
Merlin
1
Utilisez -gplutôt que -nsi vous voulez un tri numérique. -nest cassé.
Luke Hutchison le
11

Par défaut, le délimiteur de champ est une transition non vide à vide, donc la tabulation devrait fonctionner correctement.

Cependant, les colonnes sont indexées en base 1 et en base 0, donc vous voulez probablement

sort -k4nr file.txt

pour trier le fichier.txt par colonne 4 numériquement dans l'ordre inverse. (Bien que les données de la question aient même 5 champs, le dernier champ serait l'index 5.)

laalto
la source
4
Cela ne fonctionnera que si le nombre de caractères d'espacement entre les champs séparés par des tabulations est le même pour toutes les lignes d'entrée.
Lars Haugseth
5

Vous devez mettre un caractère de tabulation réel après le -t \ et pour le faire dans un shell, vous appuyez sur ctrl-v puis sur le caractère de tabulation. La plupart des shells que j'ai utilisés prennent en charge ce mode d'entrée de tabulation littérale.

Méfiez-vous cependant, car le fait de copier-coller depuis un autre endroit ne préserve généralement pas les onglets.

Brian Carlsen
la source
C'est la meilleure réponse (la plus portable). emacs vous permet également de faire cela en mode «insertion entre guillemets»: C-q <tab>par exemple. Je pense que c'est aussi ^Ven nano.
Wyatt8740
3

La solution $ n'a pas fonctionné pour moi. Cependant, en mettant réellement le caractère de tabulation lui-même dans la commande a fait: sort -t '' -k2

Lloyd
la source
1
À utiliser <C-v><Tab>pour insérer une tabulation au cas où la touche de tabulation serait utilisée pour l'auto-complétion dans votre shell.
Júda Ronén
1
Les citations ANSI $'\t'fonctionnent dans ksh, zsh et bash. Bourne shell ne le prend pas en charge. Voir cet article: unix.stackexchange.com/a/371873/201820
codeforester
1

tuyau à travers quelque chose comme awk '{ print print $1"\t"$2"\t"$3"\t"$4"\t"$5 }'. Cela changera les espaces en tabulations.

Michiel Buddingh
la source
@MB: Je dois garder l'espace intact.
neversaint
1
Il existe sans aucun doute une façon plus propre de le faire, mais rien ne vous empêche de le faire passer par awk, de changer les espaces en onglets, de trier les données, puis de les rediriger à travers awk, en changeant les onglets en espaces.
Michiel Buddingh
1
Cela ne fonctionnera pas s'il existe un mélange d'onglets et d'espaces que vous souhaitez conserver.
James Thompson
1

En général, conserver de telles données n'est pas une bonne chose à faire si vous pouvez les éviter, car les gens confondent toujours les onglets et les espaces.

Résoudre votre problème est très simple dans un langage de script comme Perl, Python ou Ruby. Voici un exemple de code:

#!/usr/bin/perl -w

use strict;

my $sort_field = 2;
my $split_regex = qr{\s+};

my @data;
push @data, "7 8\t 9";
push @data, "4 5\t 6";
push @data, "1 2\t 3";

my @sorted_data = 
    map  { $_->[1] }
    sort { $a->[0] <=> $b->[0] }
    map  { [ ( split $split_regex, $_ )[$sort_field], $_ ] }
    @data;

print "unsorted\n";
print join "\n", @data, "\n";
print "sorted by $sort_field, lines split by $split_regex\n";
print join "\n", @sorted_data, "\n";
James Thompson
la source
1

Je voulais une solution pour le tri Gnu sur Windows, mais aucune des solutions ci-dessus ne fonctionnait pour moi sur la ligne de commande.

En utilisant l'indice de Lloyd, le fichier de commandes suivant (.bat) a fonctionné pour moi.

Tapez le caractère de tabulation entre les guillemets.

C:\>cat foo.bat

sort -k3 -t"    " tabfile.txt
Lawrence Noronha
la source
1
Ouais, le truc ici est de le mettre dans un fichier .bat, sinon cela ne fonctionnera pas
Carlos Rendon
1

J'avais ce problème avec le tri dans cygwin dans un shell bash lors de l'utilisation de 'general-numeric-sort'. Si j'ai spécifié -t$'\t' -kFg, où F est le numéro de champ, cela n'a pas fonctionné, mais quand j'ai spécifié les deux -t$'\t'et -kF,Fg(par exemple -k7,7gpour le 7e champ), cela a fonctionné. -kF,Fgsans le -t$'\t'n'a pas fonctionné.

Danny
la source
0

Si vous souhaitez vous faciliter la tâche en ne disposant que d'onglets, remplacez les espaces par des onglets:

tr " " "\t" < <file> | sort <options>
Le chat impertinent
la source
Mon tr ne lit pas les fichiers, ne diffuse que XD. usage: tr [-Ccsu] string1 string2
The Unfun Cat
1
tr string1 string2 <some-file. Tout peut lire un fichier tant qu'il peut lire stdin.
Randal Schwartz
0

La réponse de Lars Haugseth n'a fonctionné qu'à partir de la ligne de commande pour moi où elle donne cette erreur si elle est exécutée à partir d'un script shell:

tri: onglet multi-caractères '$ \ t'

La solution si elle est codée dans un script shell si quelqu'un regarde est

sort -t'    '

le caractère de tabulation est entre les guillemets.

puissant et faible
la source