CLI-Adventskalender, Tag 9: Navigieren durchs Dateisystem

CLI-Adventskalender: Navigieren durchs Dateisystem

Avatar von Eric

Heute beschäftigen wir uns mit der Navigations durchs Dateisystem. Denn … es ist die ultimative Newbiehürde. Wenn wir mit der Kommandozeile anfangen, lernen wir banale Formen von elementaren Befehlen und kombinieren sie in endloser, anstrengender Monotonie.

Navigieren durchs Dateisystem

pwd
ls
cd repos
ls
cd projekt1
ls
cd ..
cd projekt2
ls

Sehr früh scheint der Fall klar zu sein: Für einfache Befehle ist die Kommandozeile vielleicht super, aber um uns auf unserer Festplatte zurechtzufinden, brauchen wir einen graphischen Dateimanager.

Oder?

Pflanzt einen Baum und dann betrachtet ihn

tree generiert eine wunderschöne Darstellung des kompletten Verzeichnisbaumes mit dem aktuellen Verzeichnis als Wurzel. Wenn das zu viel Output liefert, geht man vielleicht nur eine Ebene tiefer und beschränkt sich auf Verzeichnisse. Und vielleicht lässt man notorisch große Verzeichnisse aus.

tree -I node_modules -I .git -L 2 -d

Plötzlich hat man einen Röntgenblick und eine feingranularere Darstellung als mit dem klassischen Baum im File Explorer.

Warum zu Fuß gehen, wenn man beamen kann?

cd hat ein paar nette Features.

Mit cd ~ kommen wir zurück ins Home-Verzeichnis, mit cd - zurück ins Verzeichnis aus dem wir gerade gekommen sind.

Ein symbolischer Link – vergleichbar mit einer Verknüpfung – baut eine schnelle Abkürzung.

ln -s /home/eric/repos/projekt/src/classes/modules/awesome awesome
cd awesome

Und wie für alles andere, kann man auch für cd schnell mal ein Alias anlegen.

alias cdu="cd /home/eric/nervig/langer/verzeichnis/pfad"
cdu

Das Alias möchte man nach anfänglichem Testen vielleicht auch in seiner .bashrc verankern.

Wer faul sein möchte ohne sich auszukennen, dem helfen unsere alten Freunde find und fzf.

alias fcd='cd "$(find . -type d | fzf)"'

Warum überhaupt sich von der Stelle bewegen?

Wem ein Alias zu spezifisch ist, der kann sich die wichtigen Pfade auch in Variablen legen.

export AWESOME_PATH="/home/eric/repos/project/src/classes/modules/awesome"
cat $AWESOME_PATH/ManagerBuilderCompiler.java
rm $AWESOME_PATH/NotNeededAnymore.txt

… oder natürlich auch cd $AWESOME_PATH.

Soweit so Standard. Aber es gibt auch ein, zwei „magische“ Variablen. $CDPATH legt das Base-Verzeichnis für Verzeichniswechs fest.

export CDPATH="/home/eric/repos/project/src/classes/modules"
cd awesome

Dort lassen sich auch mehrere Verzeichnisse definieren. Man möchte vielleicht, dass die Shell zuerst im aktuellen Verzeichnis schaut. Könnte sonst nervig werden.

export CDPATH=".:/home/eric/repos/project/src/classes/modules:/home/eric/Documents"
cd awesome

Ist das nicht gleich viel angenehmer?

Mit $PATH sucht die Shell ausführbare Befehle. Es kann also geschickt sein, die eigenen Skripte dort hineinzulegen.

export PATH=$PATH:/home/eric/skripte
backup.sh

Und immer dran denken: Murks mit Umgebungsvariablen wird erst permanent, wenn es in der .bashrc landet! Ein schnelles exit rettet hier schon einmall die Situation und die gescheiterten Versuche kann man zur Reparatur aus der History fischen. Womit wir schon beim nächsten Thema wären.

Jetzt aber auch was tun!

Die häufigsten Operationen sind es zu kopieren, verschieben, löschen und Archive zu entpacken.

Zum Kopieren von – sagen wir mal – einem Verzeichnis mit vielen Dateien und einiger Größe denkt man zuerst an cp. Wenn man nicht will, dass cp die ganze Zeit stumm ist, gibt man vielleicht noch ein -v dazu und kriegt wenigstens den Namen der Datei, die aktuell kopiert wird.

cp -rv enormes_verzeichnis backup

Aber rsync wäre bei großen Aufgaben der bessere Kandidat. Komplett mit Fortschrittsanzeige und aktueller Geschwindigkeit.

rsync -ahv --info=progress2 enormes_verzeichnis backup

Anstelle von mv kann rsync mit --delete-source-files auch verschieben. Zum Testen kann man -n übergeben, um sich einen Überblick zu verschaffen, was nun eigentlich getan wird.

rsync -ahvn --info=progress2 --delete-source-files enormes_verzeichnis archiv

Löschen ist auch so ein Thema. Klar, so ein rm -rf ist schnell, effektiv und sauber, aber leider nicht so gründlich, wie es sein könnte. Wer sicher gehen will, dass eine Datei auch forensisch nicht mehr herstellbar ist, dem hilft:

shred -u -v nicht-mehr-benoetigt.txt

Leider unterstützt shred keine Verzeichnisse. Das ist ein komplett unüberwindbares Hindernis, dem wir nicht mit einer Unix-Pipe gerecht werden kö…

find ./enormes_verzeichnis -type f | xargs -I{} shred -u -v {}

Fehlen noch Archive. Es gibt so viele davon und meistens will ich mich nicht mit den Eigenheiten diverser Packprogramme beschäftigen. Ich will sie einfach nur in einen neuen Ordner auspacken, um zu vermeiden, dass sie mir meinen Download-Ordner zuspammen. Wenn ihr ähnlich faul seid, schreibt euch einfach eine Funktion in eure .bashrc, die in etwa so aussieht:

auspacken() {
  if [ ! -f "$1" ]; then
    echo "Datei nicht gefunden."
    return 1
  fi

  local archiv="$1"
  local ordner="${archiv%.*}"

  mkdir -p "$ordner"
  case "$archiv" in
    *.tar.bz2) tar -xjf "$archiv" -C "$ordner" ;;
    *.tar.gz) tar -xzf "$archiv" -C "$ordner" ;;
    *.tar.xz) tar -xf "$archiv" -C "$ordner" ;;
    *.lzma) tar --lzma -xf "$archiv" -C "$ordner" ;;
    *.bz2) bzip2 -dk "$archiv" && mv "${archiv%.*}" "$ordner" ;;
    *.rar) unrar x "$archiv" "$ordner/" ;;
    *.gz) gzip -dk "$archiv" && mv "${archiv%.*}" "$ordner" ;;
    *.tar) tar -xf "$archiv" -C "$ordner" ;;
    *.tbz2) tar -xjf "$archiv" -C "$ordner" ;;
    *.tgz) tar -xzf "$archiv" -C "$ordner" ;;
    *.zip) unzip "$archiv" -d "$ordner" ;;
    *.Z) uncompress "$archiv" ;;
    *.7z) 7z x "$archiv" -o"$ordner" ;;
    *.xz) unxz "$archiv" && mv "${archiv%.*}" "$ordner" ;;
    *.exe) cabextract "$archiv" -d "$ordner" ;;
    *) echo "Das Format kenne ich noch nicht. ^^" ; return 1 ;;
  esac
}

Ich sage es noch einmal

Wir erinnern uns an alte Bekannte aus dem Artikel zu bash. Wir haben Pfeiltaste nach oben für die letzten Befehle ,die wir so eingetippt haben, history mit dem Shortcut !42, die bash_history-Datei, die Volltextsuche mit STRG + R, sowie unsere alten Freunde

rm -rf nerviges_verzeichnis
sudo !!

und

mkdir verzeichnis
cd !$

um Befehle bzw. Parameter noch einmal zu nutzen. Hier gibt es noch mehr.

Man kann zum Beispiel schnell einen String im letzten Befehl ersetzen.

mkdir -p verzeichnis
^mkdir^cd
echo "Hello World"
^World^Mayflower

… oder vielleicht will man auch nur das n-te Argument?

mkdir -p ganz/langer/verzeichnis/baum/hinter/parameter
cd !:2

… oder ganz explizit das letzte Argument?

ps aux | sort -nrk 4 | head > processes.txt
cat !$

Eine ganze Schatzkiste voller solcher Kürzel findet man in man history.

Hüpf, hüpf, hüpf

Schon mal einen langen Befehl in bash eingegeben und ewig herumgescrollt? Bash unterstützt EMACS-Shortcuts (zsh hat einen vim-modus, vielleicht ist es Zeit für mich zu wechseln …).

  • STRG + A springt zum Anfang der Zeile
  • STRG+ E zum Ende
  • ALT + F geht ein Wort nach vorne
  • ALT + B geht ein Wort nach hinten
  • STRG + L macht dasselbe wie clear, lässt aber den Inhalt der aktuellen Zeile stehen

Es ist sogar möglich, Marks zu setzen und Makros aufzunehmen. Für Leute, die es wirklich übertreiben wollen.

man readline ist euer Freund.

Hab ich noch Platz?

Wie viel Platz hab ich noch auf meiner Partition oder meinem Stick? Was frisst gerade den ganzen Speicher? Hier helfen df -Th für eine Übersicht aller Datenträger, deren Typ, Mountpoint, Kapazität und verfügbarem Platz. Das, kombiniert mit

du -sh * | sort -rh

… liefert eine sortierte Übersicht des Speicherplatzverbrauchs aller Dateien und Verzeichnisse im aktuellen Verzeichnis.

Natürlich kann auch unser alter Freund find mit find . -type f -size +300M die Suche erheblich abkürzen.

Ich habe gemerkt, dass ich nach und nach grafische Dateimanager immer weniger benutzt habe. Vielleicht macht ihr ja eine ähnliche Erfahrung.

Shell-Weisheit des Tages
Alles ist eine Datei

Ich habe keine Quelle dafür gefunden. Es ist eine von diesen mündlichen Traditionen, die von EntwicklerIn zu EntwicklerIn weitergegeben wurden.

„In Unix, everything is a file.“

Es ist ein zentraler Designgrundsatz, der sich auch in modernen Unix-Systemen wiederfindet. Alles ist eine Datei. Jedes Gerät, das von meinem Betriebssystem erkannt wird, hat eine korrespondierende Datei. Mein Bildschirm, meine Festplatte, meine Tastatur, alle lassen sich mit Text füttern und/oder spucken Text aus.

Wenn ich ein Images meines USB-Sticks erstellen möchte geht das so:

dd if=/dev/sda1 of=/home/eric/usbstick.img bs=4M status=progress

Diese Datei kann ich mounten wie ein Laufwerk:

sudo mount -o loop /home/eric/usbstick.img /media/stick

Mit Werkzeugen wie fbi kann ich jpegs direkt in meinen Framebuffer schreiben und anzeigen, ganz ohne X-Server und ganz ohne andere Programme.

sudo fbi -d /dev/fb0 -T 1 -noverbose -a /home/eric/catpicture.jpg

Warum ist das wichtig? Weil alle Programme die wir in den letzten Tagen betrachtet haben mit Dateien interagieren. Von der niedrigsten Hardware zum abstraktesten Container, alles kann mit den Tools gesteuert werden, die wir jetzt schon kennengelernt haben. Das, mehr als alles andere, ist der Grund, warum die Shell so mächtig ist.

Avatar von Eric

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert


Für das Handling unseres Newsletters nutzen wir den Dienst HubSpot. Mehr Informationen, insbesondere auch zu Deinem Widerrufsrecht, kannst Du jederzeit unserer Datenschutzerklärung entnehmen.