So lösen Sie symbolische Links in einem Shell-Skript
Gegeben, einen absoluten oder einen relativen Pfad (in einem Unix-artigen system), würde ich mag, um zu bestimmen, die den vollständigen Pfad der das Ziel nach Behebung einer zwischengeschalteten symlinks. Bonus-Punkte für die Lösung ~username notation zur gleichen Zeit.
Wenn das Ziel ein Verzeichnis ist, könnte es möglich sein, zu chdir() in das Verzeichnis und rufen Sie dann getcwd(), aber ich wirklich wollen, dies zu tun von einem shell-Skript eher als das schreiben einer C-Helfer. Leider Schalen haben eine Tendenz, zu versuchen zu verbergen die Existenz von symlinks von den Benutzer (dies ist die bash unter OS X):
$ ls -ld foo bar
drwxr-xr-x 2 greg greg 68 Aug 11 22:36 bar
lrwxr-xr-x 1 greg greg 3 Aug 11 22:36 foo -> bar
$ cd foo
$ pwd
/Users/greg/tmp/foo
$
Was ich will, ist eine Funktion resolve (), so dass, wenn Sie ausgeführt aus dem tmp-Verzeichnis in dem obigen Beispiel, resolve("foo") == "/Users/greg/tmp/bar".
InformationsquelleAutor der Frage Greg Hewgill | 2008-08-11
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gemäß den standards
pwd -P
sollte den Pfad mit aufgelösten symlinks.C-Funktion
char *getcwd(char *buf, size_t size)
ausunistd.h
sollten das gleiche Verhalten.getcwd
pwd
InformationsquelleAutor der Antwort kauppi
Anmerkung der Redaktion: Die oben genannten Werke mit GNU
readlink
und FreeBSD/PC-BSD/OpenBSDreadlink
aber nicht auf OS X ab 10.11.GNU
readlink
bietet zusätzliche, spezifische Optionen, wie-m
für die Lösung eines symlink, ob oder nicht das ultimative Ziel nicht existiert.Hinweis: da die GNU coreutils 8.15 (2012-01-06), es ist ein realpath Programm zur Verfügung haben, ist weniger stumpf und flexibler als die oben genannten. Es ist auch kompatibel mit dem FreeBSD-util mit dem gleichen Namen. Es enthält auch Funktionen zum generieren einer relativen Pfad zwischen zwei Dateien.
[Admin-Zugabe unterhalb von Kommentar von halloleo —danorton]
Für Mac OS X (bis mindestens 10.11.x), verwenden Sie
readlink
ohne die-f
option:Editor ' s Hinweis: Dies wird nicht beheben symlinks rekursiv und somit nicht Bericht der ultimate Ziel; z.B., gegeben symlink
a
die Punkte zub
die wiederum aufc
wird dieser Berichtb
(und nicht gewährleisten, dass diese Ausgabe als eine absoluten Pfad).Verwenden Sie die folgenden
perl
Befehl auf OS X, um die Lücke der fehlendenreadlink -f
Funktionalität:perl -MCwd -le 'print Cwd::abs_path(shift)' "$path"
InformationsquelleAutor der Antwort pixelbeat
"pwd -P" scheint zu funktionieren, wenn Sie wollen einfach nur das Verzeichnis, aber wenn aus irgendeinem Grund Sie möchten, dass die Namen der tatsächlichen ausführbaren Datei, die ich glaube nicht, dass das hilft. Hier ist meine Lösung:
InformationsquelleAutor der Antwort tlrobinson
Einer meiner Favoriten ist
realpath foo
InformationsquelleAutor der Antwort Gregory
scheint zu sein, genau das, was Sie für Fragen
- es nimmt eine arbirary Weg, löst alle symbolischen Links, und gibt den "echten" Pfad
- und es ist "standard *nix", dass wahrscheinlich alle Systeme, die bereits
InformationsquelleAutor der Antwort Chuck Kollars
Setzen einige der gegebenen Lösungen zusammen, wohl wissend, dass readlink ist verfügbar auf den meisten Systemen, braucht aber verschiedene Argumente, das funktioniert gut für mich auf OSX und Debian. Ich bin mir nicht sicher über die BSD-Systeme. Vielleicht ist die Bedingung muss
[[ $OSTYPE != darwin* ]]
ausschließen-f
von OSX nur.InformationsquelleAutor der Antwort hpvw
Einen anderen Weg:
InformationsquelleAutor der Antwort Keymon
Anmerkung: ich glaube, das ist eine Feste, tragbare, ready-made-Lösung, die ist immer langen aus diesem Grund.
Unten ist eine vollständig POSIX-kompatibel Skript /Funktion , ist daher cross-Plattform (arbeitet auf macOS zu, deren
readlink
noch nicht unterstützt-f
ab 10.12 (Sierra)) - es nutzt nur POSIX-shell-Sprache-Funktionen und nur POSIX-konforme utility-Aufrufe.Es ist ein portable Implementierung des GNU
readlink -e
(die strengere version vonreadlink -f
).Können Sie laufen die Skript mit
sh
oder Quelle der Funktion inbash
ksh
undzsh
:Beispielsweise innerhalb eines Skriptes können Sie es wie folgt vor, um die Ausführung das Skript " true Verzeichnis von origin, mit aufgelösten symlinks:
rreadlink
Skript /Funktion definition:Der code wurde angepasst, mit Dankbarkeit von diese Antwort.
Ich habe auch eine
bash
-basierte stand-alone-Dienstprogramm-version hier, die Sie installieren können, mitnpm install rreadlink -g
wenn Sie Node.js installiert.Eine Tangente an Sicherheit:
jarnoin Bezug auf die Funktion, sicherzustellen, dass builtin
command
ist nicht beschattet durch ein alias oder ein shell-Funktion mit dem gleichen Namen, fragt in einem Kommentar:Die motivation hinter
rreadlink
sicherzustellen, dasscommand
hat seine ursprüngliche Bedeutung ist, es zu benutzen, um zu umgehen (benigne) Bequemlichkeit Aliase und Funktionen, die Häufig verwendet, um Schatten-standard-Befehle in interactive shells, wie die Neudefinitionls
enthalten bevorzugten Optionen.Ich denke, es ist sicher zu sagen, dass, wenn man sich mit nicht vertrauenswürdigen, schädliche Umwelt, sich Gedanken über
unalias
oderunset
- oder, für diese Angelegenheit, diewhile
do
... - neu definiert, ist nicht von Belang.Es ist etwasdass die Funktion muß sich auf seine ursprüngliche Bedeutung und Verhalten - es gibt keinen Weg darum herum.
Das POSIX-shells ermöglichen Neudefinition der gelieferten und auch die Sprache der keywords ist inhärent ein Sicherheitsrisiko (und schreiben paranoid code ist schwer im Allgemeinen).
Um Ihr Anliegen konkret:
Die Funktion beruht auf
unalias
undunset
haben Ihre ursprüngliche Bedeutung. Dass Sie neu definiert als shell-Funktionen in einer Weise verändert, Ihr Verhalten wäre ein problem; Neudefinition als alias istnicht unbedingt ein Problem, da zitieren (Teil) der name des Befehls (z.B.
\unalias
) umgeht Aliase.Jedoch, die Angabe ist nicht eine option für shell keywords (
while
for
if
do
...) und während shell keywords zu tun haben Vorrang vor shell Funktioneninbash
undzsh
Aliase haben den höchsten Vorrang, also zum Schutz gegen shell-Stichwort neudefinitionen führen Sieunalias
mit Ihrem Namen (obwohl in nicht-interaktivebash
Schalen (wie z.B. Skripte) Aliase sind nicht standardmäßig erweitert - nur, wennshopt -s expand_aliases
ist explizit genannt).Um sicherzustellen, dass
unalias
- als builtin - hat seine ursprüngliche Bedeutung, die Sie verwenden müssen\unset
es erst einmal auf, was erfordert, dassunset
haben Ihre ursprüngliche Bedeutung:unset
ist ein shell - builtinso, um sicherzustellen, dass es aufgerufen wird, die als solche würden Sie haben, um sicherzustellen, dass es sich nicht neu definiert als Funktion. Während Sie umgehen können, einen alias-Formular mit zu zitieren, die Sie nicht umgehen können ein shell-Funktion - catch-22.So, es sei denn, Sie können sich darauf verlassen
unset
zu haben, seine ursprüngliche Bedeutung, von dem, was ich sagen kann, es gibt keine garantierten Weg, um zu verteidigen gegen alle bösartigen neudefinitionen.InformationsquelleAutor der Antwort mklement0
Shell-Skripte haben oft zu finden, die Ihre "home" - Verzeichnis, auch wenn Sie aufgerufen werden, als symlink. Das Skript muss also feststellen, Ihre "Reale" position von nur $0.
auf meinem system druckt ein Skript, das folgende, das sollte ein guter Hinweis auf das, was Sie brauchen.
InformationsquelleAutor der Antwort Hugo
InformationsquelleAutor der Antwort Dave
Versuchen Sie dies:
InformationsquelleAutor der Antwort diyism
Da ich habe dieses viele Male im Laufe der Jahre, und dieses mal brauchte ich ein reines bash-portable-version, die ich verwenden könnte, auf OSX und linux, ich ging voran und schrieb:
Wohn version hier lebt:
https://github.com/keen99/shell-functions/tree/master/resolve_path
aber für den Willen ALSO, hier ist die aktuelle version (ich glaube, es ist gut getestet..aber ich bin offen für feedback!)
Könnte nicht schwer sein, damit es funktioniert für nur-bourne-shell (sh), aber ich nicht versuchen...ich mag $FUNCNAME zu viel. 🙂
hier ist ein klassisches Beispiel, Dank brew:
verwenden Sie diese Funktion, und es erfolgt die Rückkehr-real - Pfad:
InformationsquelleAutor der Antwort keen
Arbeiten rund um den Mac Inkompatibilität, kam ich mit
Nicht groß, aber auch cross-OS
InformationsquelleAutor der Antwort Clemens Tolboom
Ist Ihr Pfad ein Verzeichnis ist, oder könnte es eine Datei sein? Wenn es ein Verzeichnis ist, es ist ganz einfach:
Jedoch, wenn es vielleicht eine Datei, dann funktioniert es nicht:
weil der symlink möglicherweise beheben, in einen relativen oder einen vollständigen Pfad.
Auf Skripte, die ich brauche zu finden, der eigentliche Weg, so dass ich möglicherweise auf die Konfiguration oder andere scripts installiert zusammen mit ihm, benutze ich dieses:
Konnten Sie
SOURCE
zu jeder Datei Weg. Im Grunde, solange der Pfad ist ein symlink ist, löst es, dass der symlink. Der trick ist in der letzten Zeile der Schleife. Wenn der symlink gelöst ist absolut, es wird alsSOURCE
. Jedoch, wenn es relativ ist, es wird voranstellenDIR
für ihn, das war aufgelöst in einer realen Lage durch den einfachen trick, den ich zuerst beschrieben.InformationsquelleAutor der Antwort Daniel C. Sobral
Ich glaube, dies ist die wahre und endgültige "Lösung " symlink" ob es ein Verzeichnis oder ein nicht-Verzeichnis, die Bash benutzen:
Beachten Sie, dass alle
cd
undset
Sachen erfolgt in einer subshell.InformationsquelleAutor der Antwort solidsnack
Hier ist, wie kann man den tatsächlichen Pfad zu der Datei im MacOS/Unix mit einem eingebetteten Perl-Skript:
Ebenso, um das Verzeichnis eines symlinked-Datei:
InformationsquelleAutor der Antwort Igor Afanasyev