fcd (fast-cd) Version 1.1

Bugfix/Update nach Hinweisen von m-bostaurus.

Beim Aufruf von fcd mit bin als Zielordner erlebte m-bostaurus, dass nur 1 Verzeichnis gefunden wurde. Meine erste Vermutung, es könne daran liegen, dass zu viele Treffer gefunden werden, und die Parameterliste zu lang ist, bewahrheitete sich zwar nicht, aber mit dem Umbau, der das Problem beheben sollte, war es behoben.

Ich verwende jetzt `mapfile`, um die Suchergebnisse in ein Array zu packen.

Hier der neue Code:

#!/bin/bash
#
# fcd.sh:
#
# Fast change directory. Should be sourced from ~/.bashrc file, since it is and
# needs to be a function.
#
#	Update Ver.1.1, 2021-03-03
#		Bugfix for missing results when fast changing to "bin", thanks to m_bostaurus.
#	Update Ver.1.0, 2021-02-07
#		changed from egrep to mapfile, see code. Handles blanks in paths now flawlessly.
#   Update Ver.0.9, 2013-08-21, comments, publication
#
#   Prototyp 2010
#
# This program depends on locate/updatedb, which aren't always installed/activated.
# If you use the shell on a regular basis, you should have them installed, though.
#
#	(c) GPLv3 (2010, 2021)
#
fcd ()
{
	suchdirname=$1
	# list=$(locate $1 | egrep "/$1$"); # Version 1
    # update 12.02.2021
    # mapfile -d '' list < <(locate -b -0 -r "$suchdirname$")
    # update 19.02.2021
    mapfile -d '' list < <(locate -b -0 -r "^$suchdirname$")
    # count=$(echo $list | wc -w );
    # update 19.02.2021
    count=${#list[@]}
    case $count in
        0)
            echo "unknown directory: "$1 && return
            # could search for partial matches Doc => Documentation
        ;;
        1)
            if [[ -d "${list[0]}" ]]; 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
}

Der neue Code ist jetzt 2 Wochen bei mir im Einsatz, und funktioniert tadellos.

Wenn aber doch jmd. noch Fehler findet – immer her damit!

6 Gedanken zu „fcd (fast-cd) Version 1.1

  1. masinad

    Hi!

    Ich wollte das heute einmal ausprobieren, aber mein Usecase erfordert Verzeichnisse im Homedir. Gerade die erfasst updatedb nicht. Ich weiß, dass ich eine eigene Datenbank für mein Homedir anlegen und locate dann diese DB nutzen lassen kann. Aber hast du eine andere Idee, außer die Rechte für mein Homedir von 700 auf 755 zu setzen?

    Besten Gruß aus Hoppegarten
    Masin

    Antwort
    1. user unknown Autor

      Die Rechte des Homedirs sind auch bei mir 700, und mich interessieren auch vorwiegend, wenn auch nicht ausschließlich, Unterverzeichnisse von $HOME. Wild die Rechte zu ändern ist keine gute Idee, schon weil es nicht reversibel ist (außer man macht eine Liste, und setzt später alles von Hand zurück). Man weiß ja, wenn man alle Verzeichnisse auf 755 ändert nicht, welche vorher schon auf 755 standen.

      Updatedb wird über /etc/updatedb.conf gesteuert, da steht unter PRUNEPATHS eine Liste von Verzeichnissen, die zu boykottieren ist.
      Willst Du die nicht ändern, um locate für spezielle Zwecke zu nutzen, oder darfst Du die nicht ändern/kannst nicht?
      Ist das ein Rechner, der von mehreren Humanoiden benutzt wird (und ein anderer ist Admin)?

      `man updatedb` verrät, dass man als Benutzer eine eigene Datenbank anlegen kann, mit

      EXAMPLES
             To create a private mlocate database as an user other than root, run
                    updatedb -l 0 -o db_file -U source_directory
             Note that all users that can read db_file can get the complete list of files in the subtree of source_directory.
      

      also in Deinem Fall etwa:
      `updatedb -l 0 -o /home/masinad/masinadlocate.db -U /home/masinad`

      Den Aufruf von locate müsstest Du dann im Script noch derart ändern, dass Du auch locate Bescheid sagst, eine andere als die default-Datenbank zu benutzen, siehe:

             -d, --database DBPATH
                    Replace the default database with DBPATH.  DBPATH is a :-separated list of database file  names.   If  more  than  one
                    --database option is specified, the resulting path is a concatenation of the separate paths.
      

      Die Zeile im Script wäre dann
      `mapfile -d “ list < <(locate –database /home/masinad/masinadlocate.db -b -0 -r "^$suchdirname$")`

      oder Du setzt (evtl. nur im Script) LOCATE_PATH

             LOCATE_PATH
                    Path to additional databases, added after the default database or the databases specified using the --database option.
      

      (auch aus `man locate`).

      Darf ich fragen, wieso Dein Homedir aus dem Updatedb-PATH ausgeschlossen ist?

      Antwort
  2. masinad

    Zu deinen Fragen: Ich benutze den Rechner weitgehend allein, habe aber auch Konten für Frau und Kinder drauf, die ihn auch nutzen können.

    Ja, die man-pages habe ich mir auch angeschaut. Meine /etc/updatedb.conf sieht so aus:

    „`
    PRUNE_BIND_MOUNTS = „yes“
    PRUNEFS = „9p afs anon_inodefs auto autofs bdev binfmt_misc cgroup cifs coda configfs cpuset cramfs debugfs devpts devtmpfs ecryptfs exofs ftpfs fuse fuse.encfs fuse.sshfs fusectl gfs gfs2 hugetlbfs inotifyfs iso9660 jffs2 lustre mqueue ncpfs nfs nfs4 nfsd pipefs proc ramfs rootfs rpc_pipefs securityfs selinuxfs sfs shfs smbfs sockfs sshfs sysfs tmpfs ubifs udf usbfs vboxsf“
    PRUNENAMES = „.git .hg .svn“
    PRUNEPATHS = „/afs /media /mnt /net /sfs /tmp /udev /var/cache /var/lib/pacman/local /var/lock /var/run /var/spool /var/tmp“
    „`

    An der habe ich nix geändert und `home` wird auch nicht exkludiert.

    Ich habe das mlocate-Paket genommen, dass Archlinux als Ersatz für das locate-Paket vorsieht: https://wiki.archlinux.org/index.php/locate. updatedb kann ohne weitere Parameter nur von root aufgerufen werden, da es ansonsten keinen Schreibzugriff auf `/var/lib/mlocate/mlocate.db` hat. Rufe ich updatedb als root auf, werden wohl nur Dateien und Verzeichnisse indexiert, die user oder group root haben: https://man.archlinux.org/man/updatedb.8. Genau habe ich das noch nicht getestet.

    Von der Anpassung des Skripts habe ich bislang abgesehen, weil ich ja systemd-timer und -service für updatedb anfassen müsste. Ich kriege das zusammengeschraubt, wollte aber erstmal nachfragen, ob ich irgendwas grundlegend übersehen habe. Im Moment schiebe ich die Schuld auf möglicherweise unterschiedliche Implementationen von updatedb und locate.

    Antwort
  3. user unknown Autor

    Hy Masin,
    Zu den Unterschieden zw. mlocate/slocate und locate bin ich nicht bewandert.

    Es kommt mir merkwüdig vor, die User-Home-Verzeichnisse von der Indexierung zu excludieren. Wie hast Du gemerkt, dass Deine Verzeichnisse nicht indiziert werden – nur mit fcd, oder auch mit locate selbst?

    Bei mir wird das update aus /etc/cron.daily/mlocate täglich angestoßen. Locate ist unter xubuntu 20.04 auch eine Weiterleitung auf mlocate.

    Die von verlinkte Hilfe von updatedb scheint mir die selbe zu sein, die auf meinem System installiert ist. Ich frage mich, wie Du festgestellt hast, dass es bei Dir nicht funktioniert – doch nicht nur von diesem Absatz der php-Seite:

    > mlocate (Merging Locate) is a more secure version of the locate utility, that only shows files accessible to the user.

    Was gibt Dir denn `locate .bashrc` aus? Und was mit einem Verzeichnisnamen aus dem Hausverzeichnis, ich vermute ~/Desktop gibt es bei Arch auch.

    Was sagt `locate Desktop`, was `fcd Desktop`?

    Deine Erwähnung von systemd usw. deutet ja darauf hin, dass Du Dich ganz gut auskennst, der Vorschlag, die Rechte des Homeverzeichnisses zu ändern, dagegen nicht. Hast Du Dir vielleicht früher was verbastelt? Allerdings läuft ja der update-Dämon mit root-Rechten und kann jedes Verzeichnis indizieren, und wie wir gesehen haben, verbietet die updatedb.conf auch nichts – außer Du hättest /home auf einem exotischen Dateisystem installiert. das unter prunefs aufgelistet ist.

    Antwort
  4. masinad

    Der Vorschlag mit dem Ändern der Berechtigungen war auch eher als Extremmaßnahme gedacht. Ich mag meine 700 und würde sie gerne behalten :-D. Deswegen frage ich ja nach, warum das bei dir funktioniert und bei mir nicht.

    Nein, ich bin durch fcd zwar drauf gestoßen, habe aber auch verschiedene Tests durchgeführt, was denn locate denn nun finden kann und was nicht. Zuguterletzt habe ich mir den Hexdump der mlocate.db einmal angeschaut (´hexdump -C /var/lib/mlocate/mlocate.db | less`) und nach diversen prägnanten und ganz sicher existierenden Verzeichnissen ge-grep’t (`grep Rollenspiel /var/lib/mlocate/mlocate.db`und `grep home […]). Und tatsächlich wird kein Verzeichnis in meinem Homedir gefunden.

    Also: Verzeichnisse und Dateien abseits von /home werden gefunden, in /home nicht. Mein Homedir /home/masin existiert. `locate masin` im Wurzelverzeichnis ausgeführt liefert nur Ergebnisse in /var, aber nicht /home/masin.

    Was ich mir vielleicht noch vorstellen kann, ist, dass updatedb mein /home nicht mag, weil es ein eingehängtes btrfs-Subvolume ist. Also, meine Partition enthält ein btrfs-Dateisystem, und /home ist ein anderes Subvolume als /.
    *google*
    Und sieheda: Es ist so!

    Skipping `/home': bind mount

    Der Fehler ist bekannt:

    https://pagure.io/mlocate/issue/36 (2017)
    https://lore.kernel.org/linux-btrfs/b5e7e64a-741c-baee-bc4d-cd51ca9b3a38@gmail.com/T/ (2017)
    https://www.spinics.net/lists/linux-btrfs/msg43073.html (2015)
    https://bugzilla.redhat.com/show_bug.cgi?id=906591 (2013)

    Und setze ich PRUNE_BIND_MOUNTS = „no“ klappt das jetzt auch.

    Falls irgendwer mal irgendwann hierüber stolpern sollte: Ich habe mir zuvor mit `sudo updatedb –debug-pruning` anzeigen lassen, was alles als Bindmount ausgeschlossen wurde. Das waren bei mir zwei Pfade. In Systemen mit deutlich mehr Bind-Mounts wäre das dann vielleicht unpraktisch. Aber hier kann ich damit leben, da das zweite Bind-Mount derzeit leer ist und ggf. von Hand in die PRUNEPATHS aufgenommen werden kann.

    Persönlich sehe ich den Fehler ja bei mlocate, was verschiedene Subvolumes nicht als nicht-Bind-Mount erkennen kann. Mir ist es ja egal, ob das technisch vergleichbar gelöst ist. Das Prunen von Bind-Mounts soll dazu dienen, doppelte Einträge in der DB zu vermeiden. Hinter Subvolumes stecken aber keine doppelten Mounts gleicher Inhalte, sondern unterschiedliche Inhalte.

    Auf jeden Fall vielen Dank für dein (hoffentlich) hilfreiches Skript und deine Zeit hier in den Kommentaren. Ich kann das dann mal ausgiebig testen.

    Antwort
  5. user unknown Autor

    :fanfare:
    Super. Schön, dass Du so beharrlich warst. Manchmal wird das doch belohnt. :)

    Mit btrfs habe ich noch nicht gespielt – wird das bei Kali standardmäßig verwendet, oft, mal ja/mal nein, weißt Du nicht oder selten? Ich hoffe ich muss das niemandem erklären. :)

    Ich hoffe, dass es dann ab jetzt klappt.

    Antwort

Hinterlasse einen Kommentar

Diese Seite verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden..