Files
dx/README.md
T
2026-08-10 19:17:03 +02:00

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.