Sortieren einer tabulatorgetrennten Datei

180

Ich habe Daten mit folgendem Format:

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

Jetzt habe ich versucht, die Datei nach dem letzten Feld abnehmend zu sortieren. Ich habe die folgenden Befehle ausprobiert, aber sie wurden nicht wie erwartet sortiert.

$ 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'

Was ist der richtige Weg, um es zu tun?

Hier sind die Beispieldaten .

neversaint
quelle

Antworten:

311

Mit bash reicht dies aus:

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

Beachten Sie das Dollarzeichen vor der Zeichenfolge in einfachen Anführungszeichen. Sie können darüber in den lesen ANSI-C Zitiert Abschnitte der bash man - Seite .

Lars Haugseth
quelle
1
Verwenden '"'"' Sie diese Option , um sie in einem Alias ​​zu verwenden.
Pablo A
Können Sie zeigen, wie Sie diesen Delimeter übergeben, um innerhalb eines awk-Befehls zu sortieren? wie in awk '{print $0 | "sort -nr" > "outfile" }' datafile, außer mit einem Escape-Tabulator, der an den Sortierbefehl gesendet wird.
Merlin
11

Standardmäßig ist der Feldtrenner kein Übergang von Leer zu Leer, sodass die Registerkarte einwandfrei funktionieren sollte.

Die Spalten sind jedoch mit Basis 1 und Basis 0 indiziert, sodass Sie dies wahrscheinlich möchten

sort -k4nr file.txt

um file.txt nach Spalte 4 in umgekehrter Reihenfolge numerisch zu sortieren. (Obwohl die Daten in der Frage sogar 5 Felder haben, wäre das letzte Feld Index 5.)

laalto
quelle
4
Dies funktioniert nur, wenn die Anzahl der Leerzeichen zwischen den durch Tabulatoren getrennten Feldern für alle Eingabezeilen gleich ist.
Lars Haugseth
5

Sie müssen ein tatsächliches Tabulatorzeichen nach -t \ setzen und dazu in einer Shell Strg-V und dann das Tabulatorzeichen drücken. Die meisten Shells, die ich verwendet habe, unterstützen diesen Modus der Eingabe von wörtlichen Registerkarten.

Beachten Sie jedoch, dass beim Kopieren und Einfügen von einem anderen Ort im Allgemeinen keine Tabulatoren erhalten bleiben.

Brian Carlsen
quelle
Dies ist die beste (tragbarste) Antwort. Mit emacs können Sie dies auch im Modus "Zitiertes Einfügen" tun: C-q <tab>zum Beispiel. Ich denke, es ist auch ^Vin Nano.
Wyatt8740
3

Die $ -Lösung hat bei mir nicht funktioniert. Indem Sie jedoch das Tabulatorzeichen selbst in den Befehl einfügen, haben Sie Folgendes ausgeführt: -t '' -k2 sortieren

Lloyd
quelle
1
Verwenden Sie diese <C-v><Tab>Option, um eine Registerkarte einzufügen, falls die Tabulatortaste für die automatische Vervollständigung in Ihrer Shell verwendet wird.
Júda Ronén
1
ANSI-Zitate $'\t'funktionieren in ksh, zsh und bash. Bourne Shell unterstützt es nicht. Siehe diesen Beitrag: unix.stackexchange.com/a/371873/201820
Codeforester
1

Pfeife es durch so etwas wie awk '{ print print $1"\t"$2"\t"$3"\t"$4"\t"$5 }'. Dadurch werden die Leerzeichen in Tabulatoren geändert.

Michiel Buddingh
quelle
@ MB: Ich muss den Raum intakt halten.
Neversaint
1
Es gibt zweifellos einen saubereren Weg, dies zu tun, aber nichts hindert Sie daran, es durch awk zu leiten, die Leerzeichen in Tabulatoren zu ändern, die Daten zu sortieren und es dann erneut durch awk zu leiten und die Tabulatoren wieder in Leerzeichen umzuwandeln.
Michiel Buddingh
1
Dies funktioniert nicht, wenn Sie eine Mischung aus Tabulatoren und Leerzeichen beibehalten möchten.
James Thompson
1

Im Allgemeinen ist es nicht besonders gut, solche Daten zu behalten, wenn Sie dies vermeiden können, da die Benutzer Tabulatoren und Leerzeichen immer verwirren.

Das Lösen Ihres Problems ist in einer Skriptsprache wie Perl, Python oder Ruby sehr einfach. Hier ist ein Beispielcode:

#!/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
quelle
1

Ich wollte eine Lösung für die Gnu-Sortierung unter Windows, aber keine der oben genannten Lösungen funktionierte für mich in der Befehlszeile.

Mit Lloyd's Hinweis funktionierte die folgende Batch-Datei (.bat) für mich.

Geben Sie das Tabulatorzeichen in doppelte Anführungszeichen ein.

C:\>cat foo.bat

sort -k3 -t"    " tabfile.txt
Lawrence Noronha
quelle
1
Ja, der Trick hier ist, es in eine .bat-Datei
Carlos Rendon
1

Ich hatte dieses Problem mit der Sortierung in Cygwin in einer Bash-Shell, wenn ich 'general-numeric-sort' verwendete. Wenn ich angegeben habe -t$'\t' -kFg, wobei F die Feldnummer ist, hat es nicht funktioniert, aber als ich beide angegeben habe -t$'\t'und -kF,Fg(z. B. -k7,7gfür das 7. Feld) hat es funktioniert. -kF,Fgohne das -t$'\t'hat nicht funktioniert.

Danny
quelle
0

Wenn Sie es sich einfacher machen möchten, indem Sie nur Tabulatoren haben, ersetzen Sie die Leerzeichen durch Tabulatoren:

tr " " "\t" < <file> | sort <options>
Die Unfun Cat
quelle
Mein tr liest keine Dateien, sondern überträgt nur XD. usage: tr [-Ccsu] string1 string2
Die unfun Katze
1
tr string1 string2 <some-file. Alles kann eine Datei lesen, solange es stdin lesen kann.
Randal Schwartz
0

Die Antwort von Lars Haugseth funktionierte für mich nur über die Befehlszeile, wo sie diesen Fehler ausgibt, wenn sie über ein Shell-Skript ausgeführt wird:

sort: Registerkarte mit mehreren Zeichen '$ \ t'

Die Lösung, wenn es in einem Shell-Skript codiert ist, wenn jemand hinschaut

sort -t'    '

Das Tabulatorzeichen befindet sich zwischen dem Anführungszeichen.

mächtiger und schwacher Codierer
quelle