Comment puis-je récupérer le nom de fichier absolu dans un script shell sur Mac OS X?

19

Je voudrais récupérer le nom de fichier absolu du fichier de script actuellement exécuté. Les liens doivent également être résolus.

Sous Linux, cela semble se faire comme ceci:

$(readlink -mn "$0")

mais readlinksemble fonctionner très différemment sur Mac OS X.

J'ai lu que cela se fait en utilisant

$(realpath $0)

en BSD mais cela ne fonctionne pas non plus. Mac OS X n'en a pas realpath.

Une idée?

Huxi
la source
1
Voir cette question sur SO: stackoverflow.com/questions/799679/…
Telemachus
3
Et celui-ci: stackoverflow.com/questions/1055671/…
Télémaque le
Encore plus d'options: stackoverflow.com/questions/7665/…
Gerhard Burger

Réponses:

19

Je triche et utilise perl pour cette chose:

#!/bin/bash
dirname=`perl -e 'use Cwd "abs_path";print abs_path(shift)' $0`
echo $dirname

On pourrait penser que j'écrirais tout le script en perl, et souvent je le fais, mais pas toujours.

ericslaw
la source
Cela fonctionne, merci beaucoup. Je vous donnerai un vote positif dès que possible. Quelqu'un a-t-il une façon «pure coquille» de faire cela?
Huxi
1
J'ai bien peur que ce soit aussi bon que possible. (Compte tenu des nombreux hacks "pure shell" sur plusieurs lignes que l'on peut trouver sur Google.)
Arjan
une autre possibilité (bien que laide) est de parcourir le chemin '..', en mémorisant (par récursivité ou un tableau) jusqu'à ce que '..' renvoie le même fichier que vous venez d'avoir (c'est-à-dire: vous êtes au sommet), puis revenez en assemblant le chemin que vous allez. J'ai vu le logiciel de sauvegarde Networker de Legato faire cela pendant strace comme méthode pour obtenir un «vrai» chemin (mais peut-être pas absolu). Mais ce serait beaucoup plus de code que ci-dessus.
ericslaw
Je ne sais pas pourquoi quelqu'un a modifié le code pour utiliser $ 1 au lieu de $ 0. $ 1 n'est-il pas le premier argument du script bash? Je voulais le chemin vers le script bash en cours d'exécution, pas son premier argument.
ericslaw
27
#!/usr/bin/env bash
scriptDir="$(cd "$(dirname "$0")" && pwd -P)"
jhclark
la source
Fonctionne également sous MacOSX.
Alexar
1
C'est super! Il existe de nombreuses autres réponses trop compliquées qui flottent.
Jason S
3
Cela ne fonctionne que pour les fichiers dans un répertoire de liens symboliques, pas pour les fichiers de liens symboliques en général
Gerhard Burger
1
Il est également utile unset -v CDPATHavant le cd car le cd peut provoquer une sortie indésirable si CDPATH est défini.
Binary Phile
Pour gérer au moins une seule couche de liaison symbolique du fichier, vous pouvez également tester de manière compatible avec readlink (les macs n'ont pas -f): scriptDir=$(unset -v CDPATH; cd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE)")" && pwd -P)
Binary Phile
0

Cela gère les combinaisons de liens symboliques et fonctionne sur les fichiers et dossiers:

#!/usr/bin/env bash
realpath()
{
    if ! pushd $1 &> /dev/null; then 
        pushd ${1##*/} &> /dev/null
        echo $( pwd -P )/${1%/*}
    else
        pwd -P
    fi
    popd > /dev/null
}

Mais il ne prend pas en charge --relative-to de realpath. Cela nécessiterait la conversion décrite ici .

Oliver
la source
0

Une autre approche:

# Install.
brew install coreutils

# Use the GNU variant.
grealpath --help
FMc
la source