Vorausgesetzt, Sie haben Ausführungsberechtigungen für das aktuelle Verzeichnis - oder für das Verzeichnis, von dem aus Sie Ihr Shell-Skript ausgeführt haben -, wenn Sie nur einen absoluten Pfad zu einem Verzeichnis benötigen cd.
Schritt 10 von cd's spec
Wenn die -POption aktiviert ist, muss die $PWDUmgebungsvariable auf die Zeichenfolge gesetzt werden, die von ausgegeben werden würde pwd -P. Wenn für das neue Verzeichnis oder für ein übergeordnetes Verzeichnis dieses Verzeichnisses keine ausreichende Berechtigung zum Ermitteln des aktuellen Arbeitsverzeichnisses vorhanden ist, ist der Wert der $PWDUmgebungsvariablen nicht angegeben.
Und weiter pwd -P
Der in die Standardausgabe geschriebene Pfadname darf keine Komponenten enthalten, die auf Dateien des Typs symbolic link verweisen. Wenn es mehrere Pfadnamen gibt, die das pwdDienstprogramm in die Standardausgabe schreiben kann, wobei einer mit einem einzelnen / Schrägstrich und einer oder mehrere mit zwei / Schrägstrich beginnen, schreibt es den Pfadnamen, der mit einem einzelnen / Schrägstrich beginnt. Der Pfadname darf keine unnötigen / Schrägstriche nach den führenden ein oder zwei / Schrägstrichen enthalten.
Es ist , weil cd -Phat das aktuelle Arbeitsverzeichnis zu setzen , was pwd -Psollte sonst drucken und das cd -hat zu drucken , $OLDPWDdass folgende Arbeiten:
mkdir ./dir
ln -s ./dir ./ln
cd ./ln ; cd . ; cd -
AUSGABE
/home/mikeserv/test/ln
warte darauf...
cd -P . ; cd . ; cd -
AUSGABE
/home/mikeserv/test/dir
Und wenn ich mit cd -drucke, drucke ich $OLDPWD. cdsetzt $PWDsobald ich cd -P . $PWDjetzt einen absoluten pfad dazu habe /- also brauche ich keine weiteren variablen. Und eigentlich sollte ich nicht einmal die Hinter brauchen , .aber es gibt eine spezifizierte Verhalten Zurücksetzen $PWDauf $HOMEin einer interaktiven Shell , wenn cdschmucklos ist. Es ist also nur eine gute Angewohnheit, sich zu entwickeln.
Das oben aufgeführte Vorgehen auf dem Pfad in ${0%/*}sollte also mehr als genug sein, um $0den Pfad zu überprüfen , aber in dem Fall, dass $0es sich selbst um einen Softlink handelt, können Sie das Verzeichnis leider nicht ändern.
Hier ist eine Funktion, die das erledigt:
zpath() { cd -P . || return
_out() { printf "%s$_zdlm\n" "$PWD/${1##*/}"; }
_cd() { cd -P "$1" ; } >/dev/null 2>&1
while [ $# -gt 0 ] && _cd .
do if _cd "$1"
then _out
elif ! [ -L "$1" ] && [ -e "$1" ]
then _cd "${1%/*}"; _out "$1"
elif [ -L "$1" ]
then ( while set -- "${1%?/}"; _cd "${1%/*}"; [ -L "${1##*/}" ]
do set " $1" "$(_cd -; ls -nd -- "$1"; echo /)"
set -- "${2#*"$1" -> }"
done; _out "$1"
); else ( PS4=ERR:\ NO_SUCH_PATH; set -x; : "$1" )
fi; _cd -; shift; done
unset -f _out _cd; unset -v _zdlm
}
Es wird versucht, so viel wie möglich in der aktuellen Shell zu tun - ohne eine Subshell aufzurufen - obwohl Subshells für Fehler und Softlinks aufgerufen werden, die nicht auf Verzeichnisse verweisen. Es hängt von einer POSIX-kompatiblen Shell und einem POSIX-kompatiblen lssowie einem sauberen _function()Namespace ab. Ohne Letzteres funktioniert es immer noch einwandfrei, obwohl es dann möglicherweise überschrieben wirdunset in diesem Fall einige aktuelle Shell-Funktionen . Im Allgemeinen sollten all diese Abhängigkeiten auf einer Unix-Maschine ziemlich zuverlässig verfügbar sein.
Wird es mit oder ohne Argumente aufgerufen, wird es zunächst $PWDauf seinen kanonischen Wert zurückgesetzt. Dabei werden alle darin enthaltenen Verknüpfungen zu ihren Zielen nach Bedarf aufgelöst. Ohne Argumente angerufen und das war's auch schon; aber mit ihnen angerufen und es wird aufgelöst und kanonisiert den Pfad für jeden oder sonst eine Nachricht zu druckenstderr warum nicht.
Da es hauptsächlich in der aktuellen Shell ausgeführt wird, sollte es in der Lage sein, eine Argumentliste beliebiger Länge zu verarbeiten. Es sucht auch nach der $_zdlmVariablen (die es auch ist, unsetwenn sie durch ist) und gibt ihren C-escaped-Wert unmittelbar rechts von jedem seiner Argumente aus, auf die immer auch ein einzelnes \newline-Zeichen folgt.
Es macht eine Menge Verzeichnis zu ändern, aber, anders als es nach dem kanonischen Wert, ist es nicht beeinflussen $PWD, obwohl$OLDPWD auf keinen Fall damit gerechnet werden kann, wann es fertig ist.
Es versucht, jedes seiner Argumente so schnell wie möglich zu beenden. Es versucht zuerst cdhinein $1. Wenn dies möglich ist, wird der kanonische Pfad des Arguments zu ausgegeben stdout. Wenn dies nicht möglich ist, wird überprüft, ob $1ein Softlink vorhanden ist. Wenn dies zutrifft, wird gedruckt.
Auf diese Weise werden alle Dateitypargumente verarbeitet, zu deren Adressierung die Shell berechtigt ist, es $1sei denn, es handelt sich um einen symbolischen Link, der nicht auf ein Verzeichnis verweist. In diesem Fall wird die whileSchleife in einer Subshell aufgerufen.
Es ruft lsauf, um den Link zu lesen. Das aktuelle Verzeichnis muss zuerst auf den Anfangswert geändert werden, damit referenzierte Pfade zuverlässig verarbeitet werden können. In der Subshell für die Befehlsersetzung führt die Funktion daher Folgendes aus:
cd -...ls...echo /
Es wird lsso wenig von der linken Seite der Ausgabe entfernt, wie es erforderlich ist, um den Namen des Links und die Zeichenfolge vollständig zu enthalten ->. Ich habe zunächst versucht, dies zu vermeiden, shiftund $IFSes hat sich herausgestellt, dass dies die zuverlässigste Methode ist, soweit ich das beurteilen kann. Dies ist das gleiche, was Gilles ' poor_mans_readlink tut - und es ist gut gemacht.
Dieser Vorgang wird in einer Schleife wiederholt, bis der zurückgegebene Dateiname lsdefinitiv kein Softlink mehr ist. An diesem Punkt kanonisiert es diesen Pfad wie zuvor cdund druckt dann.
Anwendungsbeispiel:
zpath \
/tmp/script \ #symlink to $HOME/test/dir/script.sh
ln \ #symlink to ./dir/
ln/nl \ #symlink to ../..
/dev/fd/0 \ #currently a here-document like : dash <<\HD
/dev/fd/1 \ #(zlink) | dash
file \ #regular file
doesntexist \ #doesnt exist
/dev/disk/by-path/pci-0000:00:16.2-usb-0:3:1.0-scsi-0:0:0:0 \
/dev/./././././././null \
. ..
AUSGABE
/home/mikeserv/test/dir/script.sh
/home/mikeserv/test/dir/
/home/mikeserv/test/
/tmp/zshtpKRVx (deleted)
/proc/17420/fd/pipe:[1782312]
/home/mikeserv/test/file
ERR: NO_SUCH_PATH: doesntexist
/dev/sdd
/dev/null
/home/mikeserv/test/
/home/mikeserv/
Oder vielleicht ...
ls
dir/ file file? folder/ link@ ln@ script* script3@ script4@
zdlm=\\0 zpath * | cat -A
AUSGABE
/home/mikeserv/test/dir/^@$
/home/mikeserv/test/file^@$
/home/mikeserv/test/file$
^@$
/home/mikeserv/test/folder/^@$
/home/mikeserv/test/file$ #'link' -> 'file\n'
^@$
/home/mikeserv/test/dir/^@$ #'ln' -> './dir'
/home/mikeserv/test/script^@$
/home/mikeserv/test/dir/script.sh^@$ #'script3' -> './dir/script.sh'
/home/mikeserv/test/dir/script.sh^@$ #'script4' -> '/tmp/script' -> ...