fcd (fast-cd, eine Bashfunktion für Linux)

Problem:

Wie tauche ich schnell tief in ein Verzeichnis hinab? Wo finde ich ein Verzeichnis, dessen Pfad ich teilweise vergessen habe?

Lösung für eine beachtliche Teilmenge an Fällen:

fcd
Hier die Funktion als Ganzes – Erläuterung folgt unten:

fcd ()
{
  list=$(locate $1 | egrep "/$1$")
  count=$(echo $list | wc -w )
  case $count in
  0)
    echo "unknown directory: "$1 && return
    # could search for partial matches Doc => Documentation
    ;;
  1)
    if [[ -d "$list" ]]; then
    echo "1) match: $list"
    cd "$list"
    else
    echo "not a directory: $1"
    fi
    ;;
  *)
   select directory in $list "/exit/"
   do
     if [[ "$directory" = "/exit/" ]]; then break; fi
     if [[ -d "$directory" ]]; then
       echo "multi) $directory"
       cd "$directory"
       break
     else
       echo "not a directory: "$1 
     fi
   done
   ;;
  esac
}

Es ist noch nicht optimal, das Skript – es hakelt bei Verzeichnissen mit Leerstellen im Pfad wie im Verzeichnisnamen selbst. Aber lassen Sie mich erst den unproblematischen Einsatz zeigen.

Angenommen ich will in mein Bilderverzeichnis des laufenden Monats wechseln, die ich unter 1308 abgelegt habe in einem Verzeichnis irgendwo unter bilder, fotos, Bilder, Fotos oder war es Photos? Ich rufe auf  fcd 1308 und das System antwortet mir mit 1) match: /home/stefan/bilder/1308 und weil es nur ein Match gibt werde ich gleich dorthin verfrachtet.

Das war nice and easy. Grüße an Tina Turner an dieser Stelle. Sie bevorzugt es ja nice and rough. Wir behandeln aber den Fall nice and complicated. Ich will in ein Verzeichnis wechseln mit einem Namen, der nicht unique ist, und dann bietet mir das System alle Verzeichnisse dieses Namens an, und mit einer Zahl kann ich auswählen wohin ich will:

fcd postgresql
1) /etc/postgresql
2) /etc/bash_completion.d/postgresql
3) /etc/init.d/postgresql
4) /opt/postgresql
5) /usr/lib/postgresql
6) /usr/share/postgresql
7) /usr/share/doc/postgresql
8) /var/cache/postgresql
9) /var/lib/postgresql
10) /var/lib/update-rc.d/postgresql
11) /var/log/postgresql
12) /home/stefan/daten/alt/hid-workspace/sesam/ext/pgjdbc2/org/postgresql
13) /exit/
#?

Das ist bequem und der beabsichtigte Zweck des Programms, insbesondere für Ungetüme wie Nr. 12 – das wird auch mit Command-Completition zur Arbeit.

Wie arbeitet das Programm, was sind die Vorraussetzungen, was die Bugs, was die Lizenz um es zu nutzen?

* Lizenz ist die GPLv3.

* Vorraussetzung ist die Installation von locate/updatedb. Die meisten Linuxdistributionen kommen mit beidem aber in jüngster Zeit etabliert sich neumodischer Kram für grafisch geleitete Suchen, da läuft updatedb nicht mehr unbedingt. Teils wird man gar in den Shopping-Mal von Amazon umgeleitet, habe ich sagen hören. Das ist nicht nett. Updatedb, wer es noch nicht weiß, ist ein Indizierungsdienst, der alle Dateien, aber nicht pausenlos, überwacht, und im Fall dass der Rechner durchläuft eine Liste aktualisiert, in der alle Dateinamen – nicht deren Inhalt – erfasst werden. So kann sehr schnell nach Dateien gesucht werden – jedoch nicht nach den allerneuesten; die sind noch nicht erfasst.

Da der Aktualisierungsdienst regelmäßig läuft kann der Rechner auch regelmäßig zu dieser Zeit aus sein – man erinnert sich vielleicht dass Linux nach dem Unixvorbild gebaut wurde, und dieses für Großrechner entwickelt wurde, und die liefen rund um die Uhr. Und da hat man nachts, wenn wenig loswar, diese Aktualisierungen gemacht.

Neuere Dienste stellen wohl fest, ob eine Aktualisierung verpasst wurde, aber ob und wie das bei Ubuntu der Fall ist weiß ich nicht, weil bei mir der Rechner eben meist auch nachts läuft.

Und die Desktopgeschichten neueren Datums laufen wieder anders. DIe indizieren wohl auch Inhalte, damit Amazon und damit die NSA auch was davon hat.

Also was macht das Skript genau?

Es erwartet einen Parameter, $1 sucht mit locate nach dem Verzeichnis, und gibt pro Zeile eines aus – *außer das Verzeichnis hätte Zeilenumbrüche im Namen, dann geht es schief. Das Ergebnis wird aber von der Variablen list listig aufgefangen und so doch nicht ausgegeben, sondern an wc -l gereicht, was für word count -lines steht und die Zeilen, ergo Treffer* zählt.

Unterschlagen hatte ich egrep. egrep „/$1$“ ist ein extended=erweitertes grep und sucht vor dem Namen, also etwa 1308 nach einem Slash und nach dem Namen nach dem Zeilenende, um nicht /113089 oder ähnliche Häßlichkeiten zu finden. Auch Unterordner in /1308 wie /1308/lolcat  werden so unterdrückt.

Dann werden 3 Fälle unterschieden: Es gibt keinen Treffer, genau einen Trefffer, oder mehrere.

Gibt es keinen Treffer wird dies gemeldet und das Programm beendet.

Gibt es genau einen Treffer wird dies auch gemeldet und in das Verzeichnis gewechselt. -d ist ein Test ob das getestete ein Verzeichnis (directory) ist.

Gibt es mehrere Treffer werden diese plus das Wörtchen „exit“ mit dem Befehl select aufgelistet und der Variablen directory die Auswahl zugeordnet. Der User kann zwar ohnehin mit Ctrl-C jederzeit aussteigen, aber oft wird ja ein ordentlicher Ausstieg wie hier mit exit bevorzugt, da man nicht weiß, ob man sonst Dinge in Unordnung hinterlässt.

Auch hier gibt es eine Meldung und man springt ins Zielverzeichnis. Mit cd – kann man zurückspringen wenn man fertig ist.

Nun noch ein wichtiges Wort, wieso es eine Funktion ist, und kein einfaches Skript. Ein Skript gibt es auch, das sieht so aus:

#!/bin/bash
#
# find cd. For input foo, find all directories .../.../foo
# GPLv3 Stefan Wagner (2010, 2012)
#
# doesn't handle blanks in directory names gracefully.
#
fcd ()
{
  list=$(locate $1 | egrep "/$1$")
  count=$(echo $list | wc -w )
  case $count in
  0)
    echo "unknown directory: "$1 && return
    # could search for partial matches Doc => Documentation
    ;;
  1)
    if [[ -d "$list" ]]; then
    echo "1) match: $list"
    cd "$list"
    else
    echo "not a directory: $1"
    fi
    ;;
  *)
   select directory in $list "/exit/"
   do
     if [[ "$directory" = "/exit/" ]]; then break; fi
     if [[ -d "$directory" ]]; then
       echo "multi) $directory"
       cd "$directory"
       break
     else
       echo "not a directory: "$1 
     fi
   done
   ;;
  esac
}

Es besteht also aus der Funktionsdeklaration und wird von meiner  ~/.bashrc gesourced, also mittels . fcd.sh eingelesen und nötig ist das, weil ein einfaches cd in einem Skript verpufft. Es wechselt in ein anderes Verzeichnis, aber mit Ende des Skriptes ist man wieder da wo man vorher war, und das will man ja nicht – man will ja weg.

So, und wieso kracht es mit Blanks im Pfadnamen? Weil select anhand von Leerzeichen die Einträge trennt:

fcd „Ordner c“
1) /home/stefan/proj/mini/forum/tmp/firstword/Ordner  3) /exit/
2) c
#?

Wenn ich oft Ordner mit Leerstellen im Pfad hätte würde ich das Problem vielleicht angehen, aber alle diese Ordner sind in forum/tmp und alle um die Probleme mit diesen zu zeigen oder nachzustellen – nicht für Eigentliches.

Advertisements

Ein Gedanke zu „fcd (fast-cd, eine Bashfunktion für Linux)

  1. Liescheb Müller

    Eine etwas unflexiblere (Standard-) Lösung: Der Befehl „cd“ kann direkt in die Unterverzeichnisse der unter der Environment-Variable „CDPATH“ angegebene Pfade springen.

    Antwort

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.