Ich suche nach einem einfachen Befehl, der in Bash verwendet werden kann, um den absoluten und kanonisierten Pfad zu einer Datei unter OS X zu finden (ähnlich wie „readlink -f“ unter Linux).
Die folgende Beispiel-Bash-Sitzung beschreibt ein [fiktives] Dienstprogramm namens „abspath“, das das gewünschte Verhalten aufweist:
$ pwd
/Users/guyfleegman
$ ls -lR
drwxr-xr-x 4 guyfleegman crew 136 Oct 30 02:09 foo
./foo:
-rw-r--r-- 1 guyfleegman crew 0 Oct 30 02:07 bar.txt
lrwxr-xr-x 1 guyfleegman crew 7 Oct 30 02:09 baz.txt -> bar.txt
$ abspath .
/Users/guyfleegman
$ abspath foo
/Users/guyfleegman/foo
$ abspath ./foo/bar.txt
/Users/guyfleegman/foo/bar.txt
$ abspath foo/baz.txt
/Users/guyfleegman/foo/baz.txt
Wie beim letzten Aufruf von „abspath“ im obigen Beispiel wäre es mir lieber, wenn symbolische Links nicht automatisch aufgelöst würden, aber ich will hier nicht zu pingelig sein.
Antwort1
function abspath() { pushd . > /dev/null; if [ -d "$1" ]; then cd "$1"; dirs -l +0; else cd "`dirname \"$1\"`"; cur_dir=`dirs -l +0`; if [ "$cur_dir" == "/" ]; then echo "$cur_dir`basename \"$1\"`"; else echo "$cur_dir/`basename \"$1\"`"; fi; fi; popd > /dev/null; }
Beispiele:
abspath / => /
abspath /.DS_Store => /.DS_Store
abspath ~ => /Users/mschrag
cd /tmp; abspath . => /tmp
cd /; abspath .DS_Store => /.DS_Store
Antwort2
Ich glaube nicht, dass es einen integrierten Befehl gibt, der dies tut.Jesse Wilsonhabe dazu ein Bash-Skript geschrieben:
#!/bin/bash
cd -P -- "$(dirname -- "$1")" &&
printf '%s\n' "$(pwd -P)/$(basename -- "$1")"
Es funktioniert jedoch nicht gut für Pfade direkt darunter /
, wie /etc
(Drucken //etc
), sowie .
und ..
(Drucken /cwd/.
in beiden Fällen). Ich habe versucht, es zu ändern, aber mein unzureichendes Bash-Fu hat mich im Stich gelassen.
Hier ist mein Vorschlag:
#!/usr/bin/env python
import os.path
import sys
for arg in sys.argv[1:]:
print os.path.abspath(arg)
Speichern unter /usr/bin/abspath
oder so ähnlich und ausführbar machen. Beispielausgabe:
Servus08:~ danielbeck$ abspath .
/Users/danielbeck
Servus08:~ danielbeck$ abspath /tmp
/tmp
Servus08:~ danielbeck$ abspath Documents
/Users/danielbeck/Documents
Servus08:~ danielbeck$ abspath . /tmp Documents
/Users/danielbeck
/tmp
/Users/danielbeck/Documents
Wenn duTunWenn Sie eine symbolische Linkauflösung wünschen, ändern Sie die print
Zeile wie folgt:
print os.path.realpath(os.path.abspath(arg))
um dies zu erhalten:
Servus08:~ danielbeck$ abspath . /tmp Documents
/Users/danielbeck
/private/tmp
/Users/danielbeck/Documents
Antwort3
Eine Möglichkeit wäre, einfach coreutils zu installieren und zu verwenden greadlink -f
. Es löst symbolische Links auf und funktioniert mit /Foo/
oder ~/foo.txt
, wenn sie nicht vorhanden sind, aber nicht mit , /Foo/foo.txt
wenn /Foo/
nicht vorhanden ist.
$ brew install coreutils
$ greadlink -f /etc
/private/etc
$ greadlink -f ~/Documents/
/Users/lauri/Documents
$ greadlink -f ..
/Users
$ greadlink -f //etc/..////
/private
$ greadlink -f /Foo
/Foo
$ greadlink -f /Foo/foo.txt
$
Dies löst keine symbolischen Links auf und funktioniert mit /Foo/foo.txt
beiden nicht.
abspath() {
if [ -d "$1" ]; then
( cd "$1"; dirs -l +0 )
else
( cd "$(dirname "$1")"; d=$(dirs -l +0); echo "${d%/}/${1##*/}" )
fi
}
abspath /etc # /etc
abspath ~/Foo/foo.txt # doesn't work
abspath ~/Foo # works
abspath .
abspath ./
abspath ../
abspath ..
abspath /
abspath ~
abspath ~/
abspath ~/Documents
abspath /\"\ \'
abspath /etc/../etc/
abspath /private//etc/
abspath /private//
abspath //private # //private
abspath ./aa.txt
abspath aa.tar.gz
abspath .aa.txt
abspath /.DS_Store
abspath ~/Documents/Books/
dirs -l
Führt eine Tilde-Erweiterung durch. dirs +0
Druckt nur das oberste Verzeichnis, wenn sich andere Verzeichnisse im Stapel befinden.
Antwort4
Wenn Sie das Modul File::Spec für Perl installiert haben, können Sie einfach Folgendes tun:
perl -MFile::Spec -e 'print File::Spec->rel2abs("../however/complex/../you/want/to.get"), "\n"'