Mehrfachauswahl - Leertaste markiert/entmarkiert den Eintrag unter dem Cursor und rueckt eine Zeile weiter; markierte Eintraege werden fett und gelb dargestellt. - Strg+A markiert alles bzw. hebt alles auf, Esc leert die Markierung. - Die Pfadleiste oben zeigt die Anzahl markierter Eintraege je Paneel. - l/u/d arbeiten auf allen markierten Eintraegen, sonst auf dem Cursor-Eintrag, und melden anschliessend Erfolge und Fehler. - Markierungen werden bei Verzeichniswechsel und nach Transfers verworfen und beim Neuaufbau auf tatsaechlich vorhandene Eintraege eingedampft. Datei-Betrachter - Enter bzw. v oeffnet Textdateien mit Syntax-Hervorhebung; die Sprache bestimmt Pygments anhand des Dateinamens (.txt, .md, .cpp, .py, ...). - Entfernte Dateien werden dafuer in eine Temporaerdatei geladen und danach wieder entfernt. Binaerdateien und Dateien ueber 2 MiB werden abgelehnt. - Blaettern mit Pfeiltasten/Bild/Pos1/Ende, w schaltet den Umbruch, l die Zeilennummern, Esc/q schliesst. - Enter auf einer Datei setzte vorher remote_path auf die Datei selbst, was das anschliessende listdir() scheitern liess. Verbindungsdialog - Pfeiltasten wechseln jetzt zwischen den Feldern. Ein eingeklapptes Select band up/down auf show_overlay und verschluckte sie; NavSelect gibt sie an den Screen weiter, geoeffnet wird mit Enter/Leertaste. Ist das Overlay offen, behaelt es seine eigene up/down-Navigation. - Enter in einem Eingabefeld verbindet, Strg+S speichert das Profil. - Dialog bei kleinen Terminals scrollbar. Bedienmenue skaliert - Pfad- und Statusleiste hatten "height: 1" und wurden am rechten Rand abgeschnitten; sie brechen jetzt um (height: auto). - Der Footer wurde entfernt: seine Tasten reichten bei 78 Zeichen Breite bis Spalte 193 und waren zu zwei Dritteln unsichtbar. Die umbrechende Statusleiste zeigt die Belegung stattdessen vollstaendig. - Spaltenbreiten der Dateiliste richten sich nach der Paneelbreite; zuerst entfaellt das Datum, dann die Groesse. Vorher ragten die Spalten ueber das Paneel hinaus und erzeugten einen horizontalen Scrollbalken. - Fehlermeldungen stehen in einer eigenen Zeile, die nur bei Inhalt Platz belegt. Bisher wurden sie in die Statusleiste geschrieben und dort vom naechsten Cursor-Wechsel sofort wieder ueberschrieben.
14 KiB
ftptui
Interaktiver FTP- und SFTP-Client als Terminal-User-Interface in Python.
ftptui ist ein schlanker, aber vollwertiger Dateibrowser für die Kommandozeile.
Er unterstützt klassisches FTP (RFC 959, über die Python-Standardbibliothek
ftplib) sowie SFTP (SSH File Transfer Protocol, über paramiko). Damit deckt
das Tool den überwiegenden Teil der realen Dateiübertragungs-Szenarien ab –
einschließlich SSH-basiertem FTP.
Das Interface ist zweispaltig aufgebaut:
- links das lokale Dateisystem,
- rechts das entfernte System,
mit Dateiübertragung in beide Richtungen, rekursivem Hoch-/Herunterladen von Verzeichnissen, Anlegen, Umbenennen und Löschen sowie speicherbaren Verbindungsprofilen.
Inhaltsverzeichnis
- Funktionen
- Unterstützte Protokolle
- Installation
- Verwendung
- Tastaturkürzel
- Projektstruktur
- Architektur
- Konfiguration & Profile
- Entwicklung
- Testen
- Lizenz
Funktionen
- Dual-Pane-Dateibrowser – Layout und Bedienung im Stil von Total Commander / Midnight Commander: zwei benachbarte Panele (lokal & entfernt) mit den Spalten Name, Größe, Datum, einer Pfadleiste oben, einer Statusleiste unten und grün markiertem aktivem Panel.
- Klassisches Terminal-Thema – schlanker Dark-Look angelehnt an den Dateimanager ranger: schwarzer Hintergrund, Verzeichnisse grün/fett, Auswahl per inverser (hellblauer) Markierung.
- FTP über die Standardbibliothek, SFTP über
paramiko(SSH-FTP). - Herunterladen (
l) und Hochladen (u) einzelner Dateien. - Rekursive Übertragung kompletter Verzeichnisbäume.
- Verzeichnisse anlegen (
n), umbenennen (r), löschen (d), rekursives Löschen nicht-leerer Ordner. - Navigation mit Maus/Tastatur, „eine Ebene hoch“ (
←/⌫),Enteröffnet. - Verbindungsprofile werden als JSON unter
~/.config/ftptui/profiles.jsongespeichert und können wieder geladen werden. - Passwortfelder sind abgedunkelt (
password=True). - Gebaut mit dem terminalfreundlichen TUI-Framework Textual, ohne fancy Material-Design – ein „echtes“ Konsolenprogramm.
Unterstützte Protokolle
| Protokoll | Beschreibung | Bibliothek / Quelle |
|---|---|---|
ftp |
Klassisches File Transfer Protocol (RFC 959) | Standard (kein Drittpaket nötig) |
sftp |
SSH File Transfer Protocol (SSH-FTP) | paramiko |
Hinweis: „SSH-FTP“ kann zweierlei bedeuten – das SFTP-Subsystem über eine SSH-Schicht (hier umgesetzt) oder FTP über einen SSH-Tunnel (sog. „FTP over SSH“). In
ftptuiwird SFTP über SSH unterstützt, der heute übliche und sichere Weg.
Installation
Voraussetzungen
- Python ≥ 3.10
pipund idealerweise eine virtuelle Umgebung
Aus dem Quellverzeichnis
# virtuelle Umgebung anlegen und aktivieren
python3 -m venv .venv
source .venv/bin/activate
# Abhängigkeiten installieren
pip install -e .
# Abhängigkeiten (nur Laufzeit):
# textual - TUI-Framework
# paramiko - SFTP/SSH
Installations- & Deinstallations-Skripte (systemweit)
Im Projektverzeichnis liegen zwei Scripts für eine systemweite Installation
auf Debian/Ubuntu (PEP 668 „externally managed“ wird berücksichtigt: es wird eine
eigene Umgebung unter /opt/ftptui/venv angelegt und nach
/usr/local/bin/ftptui verlinkt):
./install.sh # systemweit installieren (fragt ggf. nach sudo)
./install.sh --force # erneut installieren/aktualisieren
./uninstall.sh # systemweite Installation entfernen (Nutzdaten bleiben)
./uninstall.sh --purge # zusätzlich Konfigurationsdateien löschen
Nach ./install.sh steht das Kommando ftptui global im PATH bereit.
Als Paket
pip install .
Als installiertes Kommando
Nach pip install -e . steht das Kommando ftptui global in der Umgebung bereit:
ftptui
Verwendung
-
Starten:
ftptui -
Im Verbindungsbildschirm die Daten eingeben:
- Verbindungsprofil – ein zuvor gespeichertes Profil auswählen, oder ein neues anlegen.
- Protokoll –
sftp(SSH) oderftp. - Host, Port (SFTP-Vorgabe
22, FTP-Vorgabe21), Benutzer, Passwort. - Auf Verbinden klicken. Der Port wird bei Protokollwechsel automatisch auf den jeweiligen Standard gesetzt.
-
Nach erfolgreicher Verbindung erscheint der Browser-Bildschirm mit zwei Panelen:
- links
/des lokalen Rechners bzw. das Home-Verzeichnis, - rechts das Home-/Root-Verzeichnis des entfernten Systems.
- links
-
Zwischen den Paneelen wechseln mit
Tab. Die fokussierte Tabelle erhält die Aktionen (Hoch-/Herunterladen, Umbenennen, Löschen …).
Tipp: Die Aktionen
u/lwirken auf das gerade in der fokussierten Tabelle angewählte Element und übertragen in die jeweils andere Seite.
Tastaturkürzel
Dateibrowser
| Taste | Aktion |
|---|---|
Tab |
Zwischen lokalem und entferntem Paneel wechseln |
↑ / ↓ |
Zeilenauswahl bewegen |
→ |
Ordner öffnen / Datei ansehen |
← / ⌫ |
Eine Verzeichnisebene höher |
Enter |
Ordner öffnen, Datei im Betrachter anzeigen |
↑ .. |
Eine Ebene höher (Tabellenzeile) |
Leertaste |
Eintrag markieren/abwählen (Cursor rückt weiter) |
Strg+A |
Alle Einträge markieren / Markierung aufheben |
Esc |
Markierung des aktiven Paneels aufheben |
v |
Datei im Betrachter anzeigen |
l |
Herunterladen (entfernt → lokal) |
u |
Hochladen (lokal → entfernt) |
n |
Neues Verzeichnis anlegen |
d |
Löschen (rekursiv) |
r |
Umbenennen |
q |
Beenden |
Hinweis: Hoch-/Herunterladen (
u/l), Löschen (d) und Umbenennen (r) wirken auf das aktive (grün markierte) Paneel. Wechsel der Seite mitTab. Die Pfeiltasten→/←navigieren die Verzeichnisstruktur (öffnen / eine Ebene hoch),↑/↓bewegen die Zeilenauswahl.
Mehrfachauswahl
Mit der Leertaste markierte Einträge werden fett und gelb dargestellt; die
Pfadleiste oben zeigt an, wie viele Einträge je Paneel markiert sind. Liegt eine
Markierung vor, arbeiten l, u und d auf allen markierten Einträgen,
sonst auf dem Eintrag unter dem Cursor. Nach dem Transfer bzw. beim
Verzeichniswechsel wird die Markierung zurückgesetzt.
Datei-Betrachter
Enter oder v auf einer Datei öffnet sie mit Syntax-Hervorhebung; die Sprache
wird über Pygments anhand der Endung erkannt (.txt, .md, .py, .cpp,
.json, .yml, …). Entfernte Dateien werden dafür in eine Temporärdatei
geladen und danach wieder entfernt. Binärdateien und Dateien über 2 MiB werden
abgelehnt statt angezeigt.
| Taste | Aktion |
|---|---|
Esc / q |
Betrachter schließen |
↑ / ↓ |
Zeilenweise blättern |
Bild↑ / Bild↓ |
Seitenweise blättern |
Pos1 / Ende |
Anfang / Ende |
w |
Zeilenumbruch umschalten |
l |
Zeilennummern umschalten |
Verbindungsdialog
| Taste | Aktion |
|---|---|
↑ / ↓ |
Zwischen den Eingabefeldern wechseln |
Tab |
Nächstes Feld |
Enter |
In einem Eingabefeld: verbinden; in einer Auswahlliste: Liste öffnen |
Strg+S |
Profil speichern |
Esc |
Beenden |
Projektstruktur
ftptui/
├── pyproject.toml # Paketmetadaten, Abhängigkeiten, Einstiegspunkt
├── README.md # diese Dokumentation
├── install.sh # systemweite Installation (/opt/ftptui/venv)
├── uninstall.sh # Deinstallation systemweiter Installation
├── .gitignore
└── ftptui/
├── __init__.py # Versionsnummer
├── app.py # Textual-TUI: Verbindungs- & Browser-Bildschirme
├── backend.py # Fabrik: wählt FTP- oder SFTP-Transport
├── config.py # Speicherung/Laden der Verbindungsprofile (JSON)
├── models.py # Datentypen & Transport-Protokoll
├── ftp_backend.py # FTP-Adapter (ftplib)
└── sftp_backend.py # SFTP-Adapter (paramiko)
Architektur
Die App trennt Oberfläche (Textual) von Transport (Netzwerkprotokolle) durch ein kleines Protokoll/Interface:
FileTransferBackend(inmodels.py) definiert die gemeinsame API.FTPBackendundSFTPBackendimplementieren sie.create_backend(protocol)inbackend.pyliefert den passenden Adapter.
Gemeinsame Schnittstelle (Auszug):
def connect(host, port, username, password) -> None
def listdir(path) -> list[RemoteEntry]
def chdir(path) / pwd() -> str
def download(remote, local) -> None
def upload(local, remote) -> None
def mkdir(path) / remove / rmdir / rename
def close() -> None
RemoteEntry beschreibt einen Eintrag mit name, kind (file/dir),
size und modified. Dadurch kann die Oberfläche unabhängig vom Protokoll
arbeiten – das Hinzufügen weiterer Backends (z. B. WebDAV) ist ohne Änderung
der UI möglich.
Pfadbehandlung
Beide Backends normalisieren Pfade zu absoluten Angaben relativ zum Root
des entfernten Systems. FTP-Operationen setzen das Arbeitsverzeichnis vor einer
Aktion auf /, sodass Dateiübertragungen unabhängig vom zuletzt betrachteten
Ordner zuverlässig funktionieren. SFTP nutzt absolute Pfade direkt.
Profilwertung
Profile werden als JSON in ~/.config/ftptui/profiles.json (bzw.
$XDG_CONFIG_HOME/ftptui/profiles.json) gespeichert. Das Passwort wird nur
abgelegt, wenn es entsprechend markiert wurde (aktuell standardmäßig direkt
gespeichert – Datenschutz-Hinweis siehe unten).
Konfiguration & Profile
Profile speichern: im Verbindungsbildschirm Daten eingeben und Profil speichern drücken. Gespeicherte Einträge erscheinen künftig im Dropdown Verbindungsprofil.
Beispieldatei ~/.config/ftptui/profiles.json:
[
{
"name": "git.sysdaemon.xyz",
"protocol": "sftp",
"host": "git.sysdaemon.xyz",
"port": 22,
"username": "user",
"password": "",
"save_password": false
},
{
"name": "backup-server",
"protocol": "ftp",
"host": "backup.local",
"port": 21,
"username": "ftpuser",
"password": "secret",
"save_password": true
}
]
Sicherheitshinweis: Speichern Sie Passwörter in Profilen nur auf vertrauenswürdigen Systemen. Die Datei liegt im Klartext im Benutzerverzeichnis.
Entwicklung
# Umgebung
python3 -m venv .venv && source .venv/bin/activate
pip install -e . "textual>=0.80.0" "paramiko>=3.4.0"
# Laufzeit prüfen
python -c "import ftptui; print(ftptui.__version__)"
# App booten (Konsolen-Test)
ftptui
Code-Stil & Qualität
- Typannotationen (
from __future__ import annotations) durchgängig. - Protokoll-/Interface-basierte Implementierung mit
typing.Protocol. - Keine Abhängigkeit auf Drittanbieter außer
textualundparamiko.
Testen
Die Backends werden gegen lokale Testserver end-to-end getestet:
- FTP gegen
pyftpdlib(nur für Tests; nicht Teil der Laufzeit-Abhängigkeiten), - SFTP gegen eine eigene
paramiko-SSH-Server-Implementierung.
Ablauf der Tests: Verbinden, Listings, Download, Upload, mkdir, rename,
remove, rekursives rmdir, close – für beide Protokolle.
pip install pyftpdlib
python tests/test_backends.py # Beispieldatei (siehe Entwicklung/Skripte)
Ein ausführbares Testskript kann ergänzt und an dieser Stelle dokumentiert werden; die Backends sind derart modular, dass sie ohne Terminal getestet werden können.
Lizenz
MIT – siehe Projektträger/Repositories. Keine gewerblichen Einschränkungen.
Changelog
v0.3.0
- Bugfix (Pfeil-Navigation): Im Dateibrowser navigieren die Pfeiltasten nun
im File-Manager-Stil:
←wechselt eine Ebene nach oben,→öffnet den markierten Eintrag,↑/↓bewegen die Auswahl. Zuvor verschluckte dasDataTable-Widget die Tasten (Widget-Bindings haben Vorrang). Dafür wird die neueFileTable-Klasse genutzt, dieleft/rightpassend umbindet. - Bugfix (Tab-Panel-Wechsel):
Tabwechselt jetzt zuverlässig zwischen dem lokalen und dem entfernten Paneel (expliziteaction_focus_nextstatt unzuverlässigemfocus_next). - Bugfix (
_selected): Die Auswahlauswertung liefert jetzt die Klartext-Zeichenkette statt einesrich.Text-Objekts, wodurch Öffnen/Enter nicht mehr mitAttributeErrorabstürzte. - Neu:
install.sh/uninstall.shfür systemweite Installation (PEP-668-konform via/opt/ftptui/venv+/usr/local/bin/ftptui).
v0.2.0
- Bugfix: Wechsel in den Browser-Bildschirm korrigiert
(
set_screen→switch_screen). Vorher führte eine erfolgreiche Verbindung in einenAttributeErrorund der FTP/SFTP-Client beendete sich. - Theme: Umstellung auf ein klassisches Terminal-Design im Stil von ranger (Dark-Look, grün/fette Verzeichnisse, inverse Auswahl).
- Layout: Neuaufbau als Total-Commander-artiger Dual-Pane-Browser mit Pfadleiste oben, Statusleiste unten und grün markiertem aktivem Panel.
- Datums-Spalte wird nun als lesbares Datum (
YYYY-MM-DD HH:MM) angezeigt.
v0.1.0
- Erste Veröffentlichung: FTP- & SFTP-Backends, TUI, Verbindungsprofile.
Projekt wird innerhalb der sysdaemon.xyz-Instanz über Gitea verwaltet –
https://git.sysdaemon.xyz/x3/ftptui.