Wie kann ich erreichen, dass Realpath symbolische Links nie auflöst?

Wie kann ich erreichen, dass Realpath symbolische Links nie auflöst?

Ich suche nach einem Befehl, der den absoluten Pfad einer Datei zurückgibt, ohne symbolische Links aufzulösen. realpathFunktioniert im Allgemeinen gut.

$ mkdir /tmp/test; cd /tmp/test
$ mkdir foo
$ ln -s foo bar
$ realpath -se bar           # good, this does not resolve the symlink
/tmp/test/bar

Es funktioniert auch für Dateien in symbolischen Linkverzeichnissen.

$ touch foo/file
$ realpath -se bar/file      # good, this does not resolve the symlink
/tmp/test/bar/file

Es scheitert jedoch, wenn der derzeitige DirektorIstein symbolischer Link zum Verzeichnis

$ cd bar
$ pwd
/tmp/test/bar
$ realpath -se file          # this fails, returning the target
/tmp/test/foo/file
$ realpath -se .             # this also fails, returning the target
/tmp/test/foo
$ realpath -se /tmp/test/bar/file # yet this works
/tmp/test/bar/file
$ realpath -se /tmp/test/bar # and this works
/tmp/test/bar

Warum sollte realpathsich das so verhalten? (Ist das ein Fehler?) Gibt es eine Möglichkeit, realpathden Symlink nie aufzulösen, oder gibt es eine andere Methode, die ich verwenden sollte?

Antwort1

Das aktuelle Arbeitsverzeichnis (CWD) eines Prozesses wird auf Betriebssystemebene vom vorherigen Prozess übernommen oder kann für den aktuellen Prozess mit geändert werden chdir(2). Das Betriebssystem (hier meine ich „den Kernel“) wird natürlich immer alle symbolischen Links auflösen, um das Endergebnis zu bestimmen, das ein Verzeichnis sein muss, kein symbolischer Link (zu einem Verzeichnis). Beispielsweise kann der vorherige Systemaufruf ( chdir(2)) den Fehler zurückgeben ELOOP, wenn zu viele symbolische Links aufzulösen waren. Aus Sicht des Betriebssystems kann es also kein CWD geben, das für keinen Prozess ein Verzeichnis ist: Das Betriebssystem wird es immer in den tatsächlichen Pfad auflösen, ohne dass irgendwo ein symbolischer Link vorhanden ist.

Sobald die Shell fertig ist cd /tmp/test/bar, wurde der CWD-Pfad vom Betriebssystem in aufgelöst /tmp/test/foo. Auf einem Linux-System wird beispielsweise ls -l /proc/$$/cwdder Link zum aufgelösten Pfad angezeigt, wie er vom Kernel gesehen wird: /tmp/test/foo.

Die Tatsache, dass die Shell immer noch barin ihrer Eingabeaufforderung anzeigt, liegt daran, dass sie sich an dieCDBefehl zuvor ausgeführt. Das Verhalten könnte von der Art der Shell abhängen. Ich gehe hier von Bash aus. Es ist also integriert pwd(aber nicht der externe /bin/pwdBefehl), die $PWDVariable und ihre Verwendung $PS1werden den Benutzer über das aktuelle Verzeichnis „belogen“.

Jeder Prozess, wie zum Beispiel realpathoder , /bin/pwdder von der Shell ausgeführt wird, erbt natürlich dietatsächlichCWD, das ist /tmp/test/foo. Das ist also kein Fehler in realpath, es wird nie spezifische Informationen über geben bar.

Eine mögliche umständliche Methode besteht, wie von Kusalananda vorgeschlagen, darin, die Variable irgendwie wiederzuverwenden $PWDund sie dem realpathArgument nur dann voranzustellen, wenn ihr Argument nicht bereits absolut ist.

Hier ist ein Beispiel. Ich bin mir nicht sicher, ob es nicht Möglichkeiten gibt, es zu missbrauchen. Während beispielsweise die folgende Funktion damit zurechtkäme, $PWDverhält sich die Variable selbst in Bash 4.4.12 (Debian 9) nicht gut, funktioniert aber in Bash 5.0.3 (Debian 10) einwandfrei, wenn der Pfad ein Zeilenvorschubzeichen enthält. Wenn irgendwo ein Zeilenvorschubzeichen vorhanden ist, -zsollte, um nützlich zu sein, auch eine Option hinzugefügt werden, realpathaber ich werde in diesem einfachen Beispiel nicht die gesamte Analyse der Optionen neu implementieren.

myrealpathnofollowsym () {
    for p in "$@"; do
        if ! printf '%s' "$p" | grep -q -- '^/'; then
            realpath -se "$PWD/$p"
        else
            realpath -se "$p"
        fi
    done
}

verwandte Informationen