Comment récupérer le chemin absolu d'un fichier arbitraire à partir du système d'exploitation X

Je recherche une commande simple qui peut être utilisée dans Bash pour trouver le chemin absolu et canonisé d'un fichier sur un OS X (similaire à “ readlink -f'` sous Linux).

L'exemple de session bash suivant décrit un utilitaire [fictif] appelé “ abspath'` qui présente le comportement souhaité:

$ 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 

Comme avec la dernière invocation de “ abspath'` dans l'exemple ci-dessus, je préférerais qu'il ne résolut pas automatiquement les liens symboliques, mais je ne vais pas être trop pointilleux ici.

 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; } 

Exemples:

 abspath / => / abspath /.DS_Store => /.DS_Store abspath ~ => /Users/mschrag cd /tmp; abspath . => /tmp cd /; abspath .DS_Store => /.DS_Store 

Je ne pense pas qu'il y ait une commande buildin qui fait cela. Jesse Wilson a écrit un script bash pour ceci:

 #!/bin/bash cd -P -- "$(dirname -- "$1")" && printf '%s\n' "$(pwd -P)/$(basename -- "$1")" 

Cependant, cela ne fonctionne pas bien pour les chemins directement en dessous / , comme /etc (impression //etc ), ainsi que . Et .. (impression /cwd/. Dans les deux cas). J'ai essayé de le modifier, mais mon bash-fu non suffisant m'a échoué.

Voici ma suggestion:

 #!/usr/bin/env python import os.path import sys for arg in sys.argv[1:]: print os.path.abspath(arg) 

Enregistrez sous /usr/bin/abspath ou quelque chose comme ça et rendez-le exécutable. Exemple de sortie:

 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 

Si vous voulez une résolution de lien symbolique, modifiez la ligne d' print comme ceci:

  print os.path.realpath(os.path.abspath(arg)) 

Pour obtenir ceci:

 Servus08:~ danielbeck$ abspath . /tmp Documents /Users/danielbeck /private/tmp /Users/danielbeck/Documents 

Une option serait simplement d'installer coreutils et d'utiliser greadlink -f . Il résout les liens symboliques et fonctionne avec /Foo/ ou ~/foo.txt s'ils n'existent pas, mais pas avec /Foo/foo.txt si /Foo/ n'existe pas.

 $ 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 $ 

Cela ne résout pas les liens symboliques, et cela ne fonctionne pas non plus avec /Foo/foo.txt .

 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 effectue une expansion tilde. dirs +0 imprime uniquement le répertoire supérieur s'il existe d'autres répertoires dans la pile.

Je suppose que vous pourriez le faire avec Python ou Ruby.

 $ ruby -e 'puts File.expand_path("~/somepath")' 

Ou faire une commande avec

 #!/usr/bin/env ruby puts File.expand_path(ARGV[0]) 

Si vous avez le module File :: Spec installé pour perl, vous pouvez simplement le faire:

 perl -MFile::Spec -e 'print File::Spec->rel2abs("../however/complex/../you/want/to.get"), "\n"' 

Pour les scripts bash / sh, vous pouvez utiliser cette fonction récursive:

 canonical_readlink () { cd `dirname $1`; __filename=`basename $1`; if [ -h "$__filename" ]; then canonical_readlink `readlink $__filename`; else echo "`pwd -P`"; fi } answer=$(canonical_readlink $0) 

Installez la bibliothèque suivante pour OSX:

 brew install coreutils greadlink -f file.txt