So sortieren Sie die lesbare Größe

11

Ich suche im Grunde nach Dateien und sortiere sie dann nach der Größe. Das Skript funktioniert, wenn ich die Größe nicht nach lesbar sortiere. Aber ich möchte, dass die Größe für Menschen lesbar ist. Wie kann ich Größen sortieren, die für Menschen lesbar sind?

Zum Beispiel:

 ls -l | sort -k 5 -n | awk '{print $9 " " $5}'

Dies funktioniert wie erwartet, ich habe die Größe meiner Dateien in Bytes aufsteigend erhalten:

1.txt 1
test.txt 3
bash.sh* 573
DocGeneration.txt 1131
andres_stuff.txt 1465
Branches.xlsx 15087
foo 23735
bar 60566
2016_stuff.pdf 996850

Jetzt möchte ich, dass die Größe für Menschen lesbar ist, also habe ich ls einen -h-Parameter hinzugefügt, und jetzt sind einige Dateien nicht in der richtigen Reihenfolge:

 ls -lh | sort -k 5 -n | awk '{print $9 " " $5}'
1.txt 1
DocGeneration.txt 1.2K
andres_stuff.txt 1.5K
test.txt 3
Branches.xlsx 15K
foo 24K
bar 60K
bash.sh* 573
2016_stuff.pdf 974K

tvo000
quelle
-k 5- Wie funktioniert das?
Strg-Alt-Delor
@ Strg-Alt-Delor: Ich glaube, die Größe ist in der 5. Spalte der lsAusgabe
Jesse_b
2
Verwenden dustatt lskönnte eine gute Idee sein.
Xenoid
... oder findist -printfmit seinem %pund %sFormatierer (durch eine ‚Humanisierung‘ der Größen folgen).
Stephen Kitt
@Jesse_b Mein Fehler, ich habe nur angenommen, dass die Daten in der Frage (markiert als das, was ich bekommen habe) die sortierte Eingabe waren. Ich habe mich geirrt.
Strg-Alt-Delor

Antworten:

28

Versuchen sort -h k2

-h, --human-numeric-sort vergleiche lesbare Zahlen (z. B. 2K 1G)

Es ist Teil der Gnu-Sorte, der BSD-Sorte und anderer.

Strg-Alt-Delor
quelle
5
Sollte das Parsen der Ausgabe von lsnicht vermieden werden?
3
@Tomasz Nicht immer. Wenn es die Ausgabe liefert, die Sie benötigen, ist das Weiterleiten an einen anderen Formatierungsvorgang nicht besonders gefährlich. Was Sie nicht tun sollten, ist eine Schleife über die Ausgabe von lsund verwenden stattdessen File Globbing direkt. Globbing alleine funktioniert hier nicht. Das heißt, ich würde es wahrscheinlich vorziehen du.
Bloodgain
1
@Bloodgain Es ist nicht garantiert, dass das ls-Format für alle System- / ls-Binärdateien gleich ist. Daher wird es als unmöglich angesehen, es portabel zu analysieren.
D. Ben Knoble
1
Auch Dateinamen mit Leerzeichen werden die Dinge zerstören
D. Ben Knoble
1
@Bloodgain: files=(); for f in *; do [[ -L "$f" ]] && files+=("$f"); done; echo ${#files[@]}(Ich habe möglicherweise einen falschen Symlink- Testschalter ). Wenn Sie sich nicht für Symlinks interessieren files=(*); echo ${#files[@]}, wird dieser portabel, wenn Sie setArrays verwenden und nicht.
D. Ben Knoble
29

lsWenn diese Funktionalität integriert ist, verwenden Sie die -SOption und sortieren Sie in umgekehrter Reihenfolge:ls -lShr

       -r, --reverse
              reverse order while sorting

       -S     sort by file size, largest first
Mark McKinstry
quelle
1
-hnicht um eine Standard - lsOption , aber brauchbar sein muss , wenn OP es bereits. Der Rest ist Standard und es ist sicherlich die Antwort, die ich geschrieben hätte.
Toby Speight
5
+1 Analysiere nicht die Ausgabe von ls.
David Richerby
Dies ist die beste Antwort, sollte aber die Informationen in @ Tobys Kommentar enthalten: -SMöglicherweise nicht für Sie verfügbar ls. FWIW -Swird sogar mit der Emacs-Bibliothek unterstützt ls-lisp.el, die verwendet wird, wenn das Betriebssystem keine hat ls. Es funktioniert beispielsweise in Emacs unter MS Windows.
Drew
Dies sollte die akzeptierte Antwort sein.
Streuung
1
@Drew: Tobys Kommentar besagt, dass dies -hmöglicherweise nicht universell verfügbar ist, aber OP verwendet es trotzdem. sollte-S wirklich universell verfügbar sein, da es sich um den POSIX-Link handelt, den Toby bereitstellt. Es gibt jedoch einige Nicht-POSIX-Toolkits.
Kevin
5

Da keine bestimmte Shell erwähnt wurde, gehen Sie wie zshfolgt vor:

ls -lhf **/*(.Lk-1024oL)

Das **Glob-Muster stimmt mit den Pfadnamen überein, *jedoch /wie in einer rekursiven Suche.

Der lsBefehl würde lesbare Größen mit -hund ein Langlisten-Ausgabeformat mit aktivieren -l. Die -fOption deaktiviert die Sortierung und lslistet die Dateien nur in der angegebenen Reihenfolge auf.

Diese Reihenfolge ist nach dem **/*(.Lk-1024oL)Dateinamen-Globbing-Muster angeordnet, sodass die kleineren Dateien zuerst aufgelistet werden. Das **/*Bit stimmt mit jeder Datei und jedem Verzeichnis in diesem Verzeichnis und darunter überein, (...)ändert jedoch das Verhalten des Globs (es ist ein "Glob-Qualifizierer").

Es ist das oLam Ende, das ( o) die Namen nach Dateigröße ( L, "Länge") ordnet .

Am .Anfang stimmt der Glob nur mit regulären Dateien überein (keine Verzeichnisse).

Das Lk-1024Bit wählt Dateien aus, deren Größe weniger als 1024 KB beträgt ("Länge in KB weniger als 1024").

Wenn dies zshnicht Ihre primäre interaktive Shell ist, können Sie sie verwenden

zsh -c 'ls -lf **/*(.Lk-1024oL)'

Verwenden Sie setopt GLOB_DOTS(oder zsh -o GLOB_DOTS -c ...), um auch versteckte Namen abzugleichen. ... oder einfach Dzur Glob-Qualifikationszeichenfolge hinzufügen .


Erweitern Sie das Obige unter der Annahme, dass Sie eine zweispaltige Ausgabe mit Pfadnamen und lesbaren Größen wünschen, und unter der Annahme, dass Sie über numfmtGNU-Coreutils verfügen .

zmodload -F zsh/stat b:zstat

for pathname in **/*(.Lk-1024oL); do
    printf '%s\t%s\n' "$pathname" "$(zstat +size "$pathname" | numfmt --to=iec)"
done

oder schneller,

paste <( printf '%s\n' **/*(.Lk-1024oL) ) \
      <( zstat -N +size **/*(.Lk-1024oL) | numfmt --to=iec )
Kusalananda
quelle
4

Wenn Sie sortnicht über die -hOption verfügen, können Sie einen (wenn auch sehr langen) awk-Befehl wie den folgenden verwenden:

find . -type f -size -1024k -exec ls -al {} \; | sort -k 5 -n | awk '{if ($5 > 1099511627776) {print $9,$5/1024/1024/1024/1024"T"} else if ($5 > 1073741824) {print $9,$5/1024/1024/1024"G"} else if ($5 > 1048576) {print $9,$5/1024/1024"M"} else if ($5 > 1024) {print $9,$5/1024"K"} else {print $9,$5"B"}}' | column -t

Dadurch wird Ihre Ausgabe in Bytes sortiert und anschließend in ihre lesbare Größe konvertiert.

jesse_b
quelle
-1

Würde das funktionieren?

ls -l | awk '{if ($5<=1024) {print}}' | sort -k 5 -n | awk '{print $9"\t"substr($5/1024,1,3)"k"} '| column -t

Die erste awkExp sucht nach Dateien, die kleiner als 1 MB sind, und die zweite Exp nimmt die Bytegröße aus dem Ergebnis und konvertiert sie in KB. Die ersten drei Elemente werden gedruckt, um eine für Menschen lesbare Größe zu erhalten.

Vignesh SP
quelle
Das löst die Frage des OP nicht wirklich - es sieht nur im aktuellen Verzeichnis aus und druckt nur reguläre Dateien. Wird auch mit 1 KB anstelle von 1 MB verglichen. Schließlich sind wir nach Antworten mit einer Erklärung, warum der Code funktioniert.
gro♀
Mein schlechtes fügte hinzu, was es tut.
Vignesh SP