MWCodebymw.de ↗
Terminal

Pfade und Namen zerlegen — ganz ohne basename, dirname und sed

Die Shell kann Zeichenketten selbst zerschneiden. Kein Aufruf eines externen Programms, keine Pipe – nur geschweifte Klammern. Wenn du das einmal kennst, werden deine Skripte kürzer und deutlich schneller.

Ich habe jahrelang basename und dirname benutzt, ohne zu wissen, dass die Shell das selbst kann. In einer Schleife über tausend Dateien macht das einen spürbaren Unterschied: Jeder Aufruf startet einen eigenen Prozess. Die eingebaute Variante braucht keinen.

Die vier, die du dauernd brauchst

pfad="/var/www/kunde/bilder/logo.klein.png"

echo "${pfad##*/}"     # logo.klein.png   – alles bis zum letzten /  weg
echo "${pfad%/*}"      # /var/www/kunde/bilder – ab dem letzten / weg
echo "${pfad##*.}"     # png              – die Endung
echo "${pfad%.*}"      # /var/www/kunde/bilder/logo.klein – Endung weg

Die Logik dahinter ist simpel, wenn man sie einmal sieht:

  • # schneidet vorne ab, % schneidet hinten ab.
  • Einmal (#, %) heißt kürzestmöglich, doppelt (##, %%) heißt längstmöglich.

Deshalb liefert ${pfad%.*} bei logo.klein.png genau logo.klein — es wird nur die letzte Endung entfernt. ${pfad%%.*} würde dagegen ab dem ersten Punkt kürzen und logo übrig lassen.

⚠️ Eine Falle, die du kennen solltest: Enthält die Zeichenkette gar kein /, dann gibt ${pfad%/*} den kompletten Wert zurück, nicht etwa . wie bei dirname. Bei blanken Dateinamen also lieber vorher prüfen.

Vorgabewerte statt if-Kaskaden

ziel="${1:-./build}"              # erstes Argument, sonst ./build
echo "Baue nach $ziel"

: "${API_TOKEN:?API_TOKEN fehlt – bitte in der Umgebung setzen}"

Die erste Zeile ersetzt drei Zeilen if. Die zweite bricht das Skript mit einer verständlichen Meldung ab, wenn die Variable fehlt oder leer ist — genau das, was man bei Zugangsdaten will, statt später einen kryptischen Fehler aus dem Programm zu bekommen. Das : davor ist der Nichts-tu-Befehl; er wertet nur die Erweiterung aus.

Ersetzen und zählen

name="Mein Kunden Projekt"

echo "${name// /-}"    # Mein-Kunden-Projekt   – alle Treffer
echo "${name/ /-}"     # Mein-Kunden Projekt   – nur der erste
echo "${#name}"        # 19                    – Länge
echo "${name,,}"       # mein kunden projekt   – klein
echo "${name^^}"       # MEIN KUNDEN PROJEKT   – groß

${name,,} und ${name^^} brauchen Bash 4 oder neuer. Auf einem aktuellen Linux ist das kein Thema; auf dem alten macOS-Bash (3.2) fehlt es — dort hilft tr '[:upper:]' '[:lower:]'.

Ein Beispiel, das ich wirklich benutze

Bilder für den Web-Einsatz umwandeln und dabei den Namen behalten:

#!/usr/bin/env bash
set -euo pipefail

for bild in bilder/*.{jpg,png}; do
    [ -e "$bild" ] || continue          # kein Treffer? Muster überspringen
    datei="${bild##*/}"                 # kunde-logo.png
    ohne="${datei%.*}"                  # kunde-logo
    cwebp -quiet -q 82 "$bild" -o "web/${ohne}.webp"
    echo "→ web/${ohne}.webp"
done

Kein basename, kein sed, keine Subshell. Bei ein paar Dateien merkst du nichts — bei ein paar tausend schon.

Solche kleinen Skripte sind bei mir Alltag: Bilder aufbereiten, Backups wegräumen, Deployments anstoßen. Wenn du sowas für dein Projekt brauchst oder deine Website ohnehin mal jemand ansehen sollte, melde dich gern über bymw.de.

Quellen

#Bash#Strings#Pfade#Terminal

Du brauchst mehr als ein Snippet?

Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.

Projekt anfragen →