220 lines
9.0 KiB
Markdown
220 lines
9.0 KiB
Markdown
# dx
|
|
|
|
Zählt, was in einem Verzeichnis liegt, und wie schwer es ist — eine Ebene tief,
|
|
ein Blick, sofort fertig.
|
|
|
|
```
|
|
$ dx ~/src -r -t 8
|
|
/Users/mike/src 2489 1.1G
|
|
Wetter/ 297 316M ██▉ 29%
|
|
gblog/ 99 135M █▎ 12%
|
|
gbld/ 82 131M █▏ 12%
|
|
goca/ 80 108M █ 10%
|
|
futterturm/ 62 68M ▋ 6%
|
|
BugSim/ 323 68M ▋ 6%
|
|
gvm/ 37 57M ▌ 5%
|
|
mJournal/ 204 42M ▍ 4%
|
|
… 16 more 1305 179M █▋ 16%
|
|
```
|
|
|
|
Links der Name, dann die Zahl der enthaltenen Dateien, dann die Summe ihrer
|
|
Größen, dann der Anteil am Ganzen. Die Kopfzeile ist das Verzeichnis selbst.
|
|
Verzeichnisse werden vollständig durchlaufen, aber nicht aufgeklappt — für
|
|
alles Weitere ist `ncdu` da.
|
|
|
|
Im Terminal ist die Ausgabe farbig, nach der Palette aus
|
|
[mwxcol](../mwxcol/README.md).
|
|
|
|
## Bauen und installieren
|
|
|
|
```sh
|
|
cd ~/src/dx
|
|
./build.sh
|
|
cp bin/dx ~/bin/dx
|
|
```
|
|
|
|
`build.sh` baut nach `./bin`, je ein Binary für macOS und Linux auf arm64 und
|
|
amd64, und legt `bin/dx` als Symlink auf das für diese Maschine. Für eine
|
|
einzelne Plattform:
|
|
|
|
```sh
|
|
PLATFORMS="linux/amd64" ./build.sh
|
|
```
|
|
|
|
Jeder Lauf zählt die Patch-Nummer in `version.txt` um eins hoch und baut sie
|
|
per `-ldflags` in alle Binaries ein — `dx --version` sagt also, welcher Bau
|
|
läuft. Ein nacktes `go build` geht auch, meldet dann aber die Vorgabe aus
|
|
`main.go` statt der wirklichen Nummer.
|
|
|
|
Braucht Go ≥ 1.26 und `github.com/fatih/color`. Das Perl-Original (`dx`, 1.0.2,
|
|
2016) liegt unverändert daneben und wird vom Bau nicht angefasst; es hat keine
|
|
Farben und keine Balken, tut aber sonst dasselbe.
|
|
|
|
## Selbst aktualisieren
|
|
|
|
```sh
|
|
dx --check-update # nur nachsehen
|
|
dx --update # holen und ersetzen
|
|
```
|
|
|
|
`dx` holt sich das neueste Release von
|
|
[git.micw.org/mike/dx](https://git.micw.org/mike/dx) — die URL steht fest im
|
|
Programm, es gibt nichts zu konfigurieren. Gebraucht wird ein Release je
|
|
Version, dessen Tag die nackte Nummer ist (`2.1.6`), mit den Dateien aus `./bin`
|
|
als Assets; gesucht wird die eine, die zu `GOOS`/`GOARCH` dieser Maschine passt.
|
|
|
|
Ersetzt wird die laufende Datei selbst. Ist der aufgerufene `dx` ein Symlink —
|
|
etwa `~/bin/dx` auf `~/src/dx/bin/dx-darwin-arm64` —, wird das Ziel dahinter
|
|
erneuert, nicht der Link. Vor dem Tausch wird das frisch Geladene einmal mit
|
|
`--version` aufgerufen; meldet es nicht die erwartete Nummer, bleibt alles, wie
|
|
es war. Der Tausch selbst ist ein `rename` im selben Verzeichnis, also atomar:
|
|
entweder die alte Datei oder die neue, nie eine halbe.
|
|
|
|
Liegt das Binary irgendwo, wo der eigene Benutzer nicht schreiben darf
|
|
(`/usr/local/bin`), sagt `dx --update` das und tut nichts — dann `sudo`.
|
|
|
|
## Wiederverwenden
|
|
|
|
`selfupdate.go` hängt an nichts im Rest des Programms und kommt mit der
|
|
Standardbibliothek aus. Für ein anderes Programm die Datei kopieren, den Block
|
|
oben anpassen —
|
|
|
|
```go
|
|
var selfUpdate = selfUpdater{
|
|
repo: "https://git.micw.org/mike/foo",
|
|
asset: "foo",
|
|
current: version,
|
|
verify: []string{"--version"},
|
|
}
|
|
```
|
|
|
|
— und `--update` und `--check-update` in die Optionen hängen. Alles Weitere in
|
|
der Datei heißt `selfUpdate…` oder `update…` und kollidiert deshalb nicht.
|
|
`verify` leer lassen, wenn das Programm keinen billigen Versionsaufruf hat; dann
|
|
entfällt der Probelauf. Erwartet wird eine Gitea-Instanz (getestet mit 1.27);
|
|
GitHub kennt dieselbe Route unter anderen Feldnamen und wird nicht bedient.
|
|
|
|
## Optionen
|
|
|
|
| | | |
|
|
|---|---|---|
|
|
| `-n` | `--number` | nach Dateizahl sortieren statt nach Größe |
|
|
| `-d` | `--dirs` | nur Verzeichnisse zählen, Dateien der obersten Ebene weglassen |
|
|
| `-r` | `--reverse` | größtes zuerst |
|
|
| `-t N` | `--top=N` | nur die N größten zeigen, den Rest zu einer Zeile summieren |
|
|
| `-h` | `--help` | Hilfe |
|
|
| | `--bar`, `--no-bar` | Balken und Prozent erzwingen bzw. abschalten |
|
|
| | `--color=auto\|always\|never` | Farbe erzwingen bzw. abschalten |
|
|
| | `--version` | Version |
|
|
| | `--check-update` | nachsehen, ob ein neueres Release da ist |
|
|
| | `--update` | neuestes Release holen und installieren |
|
|
|
|
Kurzoptionen lassen sich bündeln (`-rt 3`, `-dn`), der Wert von `-t` darf kleben
|
|
(`-t5`) oder folgen (`-t 5`). Ein `--` trennt Optionen von einem Pfad, der mit
|
|
`-` beginnt. Ohne Pfad gilt das aktuelle Verzeichnis.
|
|
|
|
Sortiert wird aufsteigend, das Größte steht also direkt über dem Prompt und man
|
|
muss nicht scrollen. `-r` dreht das um, für Pipes und lange Listen.
|
|
|
|
Bei `-t` steht die Sammelzeile immer am kleinen Ende: oben bei normaler
|
|
Sortierung, unten bei `-r`.
|
|
|
|
| Exit | |
|
|
|---|---|
|
|
| 0 | alles gelesen |
|
|
| 1 | Pfad existiert nicht oder ist kein Verzeichnis |
|
|
| 2 | Option falsch benutzt |
|
|
|
|
## Farbe und Balken
|
|
|
|
Beides gilt am Terminal und entfällt in einer Pipe — `dx | sort` bekommt reinen
|
|
Text. `--color=always` schaltet beides wieder ein, für `less -R`. Wer nur eins
|
|
davon will, sagt es mit `--bar` / `--no-bar` ausdrücklich. `NO_COLOR` wird
|
|
beachtet.
|
|
|
|
Die Farben folgen den `file_type`-Rollen aus `themes/eza/theme.yml`, damit
|
|
dieselbe Datei in `eza` und `dx` gleich aussieht:
|
|
|
|
| | | | | |
|
|
|---|---|---|---|---|
|
|
| Verzeichnis | blue, fett | | Archive | orange |
|
|
| ausführbar | green, fett | | Bilder | violet |
|
|
| Symlink | pink | | Video | pink |
|
|
| Quelltext, Konfiguration | blue | | Audio | green |
|
|
| README, Makefile, `go.mod` | yellow | | Schlüssel, Zertifikate | red |
|
|
| Dokumente | white | | Kompilate (`.o`, `.dylib`) | grey |
|
|
| sonstige Dateien | white | | `.tmp`, `.bak`, `.DS_Store` | darker |
|
|
|
|
Die Zahlenspalte ist grey, eine Null dark. Die Größenspalte trägt die
|
|
Größenrampe des eza-Themes — bis K green, M yellow, G orange, T red — und der
|
|
Balken nimmt die Farbe der Spalte auf, deren Anteil er zeigt: die der Größe,
|
|
mit `-n` die der Dateizahl.
|
|
|
|
Der Balken ist zehn Zellen breit und rechnet in Achteln (`▏▎▍▌▋▊▉█`). Was
|
|
weniger als ein halbes Prozent ausmacht, bekommt keinen Strich und steht als
|
|
`<1%` da statt als geschöntes `0%`. Dadurch bleiben genau die Zeilen sichtbar,
|
|
auf die es ankommt.
|
|
|
|
## Größen
|
|
|
|
Die Schwellen sind die des Originals: ab 1024 der jeweiligen Einheit wird
|
|
umgeschaltet. Unterhalb von 10 kommt eine Nachkommastelle dazu, weil `2G` sonst
|
|
alles zwischen 1,5 und 2,4 Gigabyte bedeuten könnte. Ganze Bytes bleiben ganz.
|
|
|
|
8 4.9K 316M 1.1G
|
|
|
|
## Was genau gezählt wird
|
|
|
|
Gezählt werden **reguläre Dateien**, wie bei `find -type f`. Verzeichnisse,
|
|
Sockets, Fifos und Geräte zählen nicht mit, auch nicht die Verzeichnisse selbst.
|
|
|
|
* Ein **Symlink auf ein Verzeichnis** wird nicht verfolgt und steht deshalb mit
|
|
`0` da — pink eingefärbt, damit die Null erklärt ist.
|
|
* Ein **Symlink auf eine Datei** auf oberster Ebene zählt mit der Größe seines
|
|
Ziels, ebenfalls pink.
|
|
* **Hardlinks** zählen so oft, wie sie vorkommen. In einem Baum mit
|
|
`rsync --link-dest` oder Time Machine sind die Zahlen dadurch zu hoch; für so
|
|
etwas ist `dx` nicht gedacht.
|
|
* Gemessen wird die **Dateigröße**, nicht der belegte Platz. Sparse-Dateien und
|
|
APFS-Klone erscheinen größer, als sie auf der Platte sind.
|
|
* Was sich nicht lesen lässt — gesperrte Verzeichnisse, tote Symlinks — wird
|
|
übersprungen und am Ende auf **stderr** gemeldet, damit die Tabelle heil
|
|
bleibt.
|
|
* `-d` lässt Dateien der obersten Ebene ganz weg, auch aus der Summe.
|
|
|
|
Unterverzeichnisse werden nebenläufig durchlaufen, so viele auf einmal wie
|
|
Kerne da sind. Das Original startete pro Verzeichnis einen `find`-Prozess; auf
|
|
`~/go` sind das 0,19 s statt 0,34 s.
|
|
|
|
## Unterschiede zum Perl-Original
|
|
|
|
1. **Gleichstände sortieren nach Namen.** Perl ließ sie in der Reihenfolge des
|
|
Hashes, `dx -n` gab bei jedem Aufruf eine andere Reihenfolge aus.
|
|
2. **Ein ungültiger Pfad ist ein Fehler.** Perl listete stillschweigend das
|
|
aktuelle Verzeichnis — plausible, aber falsche Zahlen.
|
|
3. **Die Namensspalte ist eine Stelle breiter**, wenn der längste Eintrag ein
|
|
Verzeichnis ist. Perl zählte den angehängten `/` bei der Spaltenbreite nicht
|
|
mit, der längste Name klebte am Zahlenblock.
|
|
4. **Fehler stehen auf stderr**, statt als `find: … Permission denied` mitten in
|
|
der Ausgabe.
|
|
5. **Größen haben eine Nachkommastelle**, siehe oben. Das ist die einzige
|
|
Abweichung im alten Ausgabeformat; ohne Farbe und Balken ist der Rest
|
|
byteweise identisch.
|
|
|
|
Neu sind `-r`, `-t`, die Balkenspalte, die Farben und die langen Optionen.
|
|
|
|
## Aufbau
|
|
|
|
| Datei | |
|
|
|---|---|
|
|
| `main.go` | Zählen, Sortieren, Formatieren, Optionen |
|
|
| `filetypes.go` | Endung und Dateiname → Farbe |
|
|
| `selfupdate.go` | `--update`, eigenständig und zum Kopieren gedacht |
|
|
| `build.sh` | Bau für alle Plattformen, zählt `version.txt` hoch |
|
|
| `version.txt` | die zuletzt gebaute Version |
|
|
| `dx` | das Perl-Original von 2016 |
|
|
|
|
Die Palette steht in `main.go` doppelt — einmal als Zahlenwerte, einmal in den
|
|
Kommentaren als Rolle. Quelle der Wahrheit bleibt `~/src/mwxcol/mwxcol.go`;
|
|
ändert sie sich dort, müssen die elf `rgb{…}` hier nachgezogen werden.
|