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 -P
Option aktiviert ist, muss die $PWD
Umgebungsvariable 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 $PWD
Umgebungsvariablen 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 pwd
Dienstprogramm 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 -P
hat das aktuelle Arbeitsverzeichnis zu setzen , was pwd -P
sollte sonst drucken und das cd -
hat zu drucken , $OLDPWD
dass 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
. cd
setzt $PWD
sobald ich cd -P .
$PWD
jetzt 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 $PWD
auf $HOME
in einer interaktiven Shell , wenn cd
schmucklos 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 $0
den Pfad zu überprüfen , aber in dem Fall, dass $0
es 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 ls
sowie 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 $PWD
auf 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 $_zdlm
Variablen (die es auch ist, unset
wenn sie durch ist) und gibt ihren C-escaped-Wert unmittelbar rechts von jedem seiner Argumente aus, auf die immer auch ein einzelnes \n
ewline-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 cd
hinein $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 $1
ein Softlink vorhanden ist. Wenn dies zutrifft, wird gedruckt.
Auf diese Weise werden alle Dateitypargumente verarbeitet, zu deren Adressierung die Shell berechtigt ist, es $1
sei denn, es handelt sich um einen symbolischen Link, der nicht auf ein Verzeichnis verweist. In diesem Fall wird die while
Schleife in einer Subshell aufgerufen.
Es ruft ls
auf, 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 ls
so 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, shift
und $IFS
es 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 ls
definitiv kein Softlink mehr ist. An diesem Punkt kanonisiert es diesen Pfad wie zuvor cd
und 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' -> ...