Sortieren Sie eine Datei nach einem Feld, das mit einer Zeichenfolge beginnt

Sortieren Sie eine Datei nach einem Feld, das mit einer Zeichenfolge beginnt

Angenommen, ich habe eine Datei so strukturiert

/home/zz/AUTHORBOOKS/Author-Chomsky-Who-Rules-the-World.epub
/home/zz/AUTHORBOOKS/Author-Cioran-Il-nulla.epub
/home/zz/BOOKS/Author-Artemis-Mathematica-Examples.nb
/home/zz/Books/Author-Zigniwe-Hisory-Medicine.pdf
/home/z1/OLDBOOKS1/OLDBOOKS2/Author-Watanabe-Waterloo.pdf
/home/z2/OLDBOOKS1/OLDBOOKS2/Author-Barbero-Lepanto.epub.pdf

Ich hätte gerne eine folgendermaßen sortierte Datei:

/home/zz/BOOKS/Author-Artemis-Mathematica-Examples.nb
/home/z2/OLDBOOKS1/OLDBOOKS2/Author-Barbero-Lepanto.epub.pdf
/home/zz/AUTHORBOOKS/Author-Chomsky-Who-Rules-the-World.epub
/home/zz/AUTHORBOOKS/Author-Cioran-Il-nulla.epub
/home/z1/OLDBOOKS1/OLDBOOKS2/Author-Watanabe-Waterloo.pdf
/home/zz/Books/Author-Zigniwe-History-Medicine.pdf

Das heißt, alphabetisch nach der ZeichenfolgeAuthor-...

Wie Sie sehen, Author-...ist die Position nicht konstant.

Wie kann ich das machen?

Antwort1

Versuchen Sie den folgenden bashBefehl:

sort -t- -d -k2 -o output.txt input.txt

Es gibt vier Optionen plus den Namen der Eingabedatei input.txt. Wenn sich diese Datei nicht im aktuellen Verzeichnis befindet, müssen Sie sie angeben path/to/the/folder/input.txt. Die Optionen und ihre Argumente lauten wie folgt:

  • -t markiert den Feldtrenner. Wir verwenden -als Trennzeichen, sodass alles davor und danach als -separate Spalten betrachtet wird.
  • -d gibt die Wörterbuchsortierung an. Beispielsweise steht Apple vor Berry.
  • -k2 gibt die Spalte an, nach der sortiert werden soll, in diesem Fall die zweite Spalte. Beachten Sie, dass die erste Spalte alles vor der ersten ist -. Zum Beispiel /home/zz/BOOKS/Author. Die zweite Spalte liegt zwischen der ersten und der zweiten -, also Artemis.
  • -o output.txtleitet die sortierte Ausgabe in eine Datei statt an das Terminal um.

Hoffe das hilft

Antwort2

Obwohl es für das vorliegende Beispiel übertrieben ist, weilLösung vorgeschlagen in der Antwort von user68186, Sie könnten allgemeiner so etwas in GNU awk tun:

gawk -F/ '
  function mycmp(i1,v1,i2,v2) {
    m = split(v1,a);
    n = split(v2,b);
    return a[m]"" > b[n]"" ? 1 : a[m]"" < b[n]"" ? -1 : 0
  }
  {
    lines[NR] = $0
  }
  END {
    PROCINFO["sorted_in"] = "mycmp";
    for(i in lines) print lines[i]
  }
' file

Beachten Sie, dass nach dem lexikalischen Wert von allem nach dem letzten sortiert wird /. Wenn das Format Author-<author name>-<title>.<extension>also

  • die feste Zeichenfolge Author-(die keine Auswirkung hat, da sie für alle Zeilen das gleiche Gewicht hat); dann
  • <author name>-; Dann
  • <title>.; Dann
  • <extension>

Dies ähnelt der Funktionsweise sortdes einfachen KEYDEF von GNU -t- -k2, d. h. der effektive Sortierschlüssel beginnt <author name>und reicht bis zum Zeilenende.

Ein explizites Trennzeichen wird bei den splitAufrufen weggelassen, sodass sie den Wert von erben FS. Dies erleichtert die Änderung für Systeme, die ein anderes Pfadtrennzeichen verwenden. Die angehängten leeren Zeichenfolgen ""in der mycmpFunktion erzwingen einen lexikalischen Vergleich, selbst wenn die Dateinamen numerisch sind - siehe beispielsweiseWie awk zwischen Zeichenfolgen und Zahlen konvertiert


Wenn Sie lieber beim sortBefehl bleiben möchten, können Sie GNU awk's nutzenZweiwegekommunikation mit einem anderen ProzessZu:

  • dupliziere das letzte /-getrennte Feld am Anfang der Zeichenfolge
  • Übergeben Sie das Ergebnis an einen sortBefehl
  • das Sortierergebnis zurücklesen, das doppelte Präfix entfernen und drucken

dh

gawk -F/ '
  BEGIN {OFS=FS; cmd = "sort -d"} 
  {print $NF $0 |& cmd} 
  END {
    close(cmd,"to"); 
    while(cmd |& getline){$1 = ""; print};
    close(cmd,"from")
  }
' file

Hier wird ein bisschen geschummelt, da die absoluten Pfade (Zeilen beginnen mit /) ein anfängliches leeres Feld implizieren. Um relative Pfade verarbeiten zu können, müssten Sie zu ändern, print $NF $0um das „fehlende“ Trennzeichen einzufügen, und dann vielleicht einen regulären Ausdruck anstelle der einfacheren Methode print $NF,$0verwenden, um das führende Element zu entfernen.sub()$1 = ""

Dies ist nicht nur potenziell schneller/speichereffizienter als die reine gawkLösung, sondern ermöglicht auch sortdas einfache Hinzufügen weiterer Optionen, z. B. cmd = "sort -d -t " FS " -k1,1r".

verwandte Informationen