Ruta absoluta del script Bash con OSX

Estoy tratando de obtener la ruta absoluta a la secuencia de comandos en ejecución en OS X.

Vi muchas respuestas para readlink -f $0 . Sin embargo, dado que el readlink OS X es igual que BSD, simplemente no funciona (funciona con la versión de GNU).

¿Alguna sugerencia para una solución lista para usar?

Hay una realpath() C que hará el trabajo, pero no veo nada disponible en la línea de comandos. Aquí hay un reemplazo rápido y sucio:

 #!/bin/bash realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" } realpath "$0" 

Esto imprime la ruta textualmente si comienza con un / . Si no, debe ser una ruta relativa, por lo que precede $PWD al frente. La #./ Parte elimina ./ del frente de $1 .

Estos tres sencillos pasos resolverán este y muchos otros problemas de OSX:

  1. Instalar Homebrew
  2. brew install coreutils
  3. grealpath .

(3) puede cambiarse a solo realpath , ver (2) salida

Ugh. Las respuestas anteriores me parecieron un poco deficientes por algunas razones: en particular, no resuelven múltiples niveles de enlaces simbólicos, y son extremadamente “Bash-y”. Si bien la pregunta original sí pide explícitamente un “guión Bash”, también menciona el readlink de Mac OS X que no es de GNU. Así que aquí hay un bash de una portabilidad razonable (lo he comprobado con bash como ‘sh’ y dash), resolviendo una cantidad arbitraria de enlaces simbólicos; y también debería funcionar con espacios en blanco en la (s) ruta (s), aunque no estoy seguro del comportamiento si hay espacio en blanco, el nombre base de la utilidad en sí, así que tal vez, um, ¿evitar eso?

 #!/bin/sh realpath() { OURPWD=$PWD cd "$(dirname "$1")" LINK=$(readlink "$(basename "$1")") while [ "$LINK" ]; do cd "$(dirname "$LINK")" LINK=$(readlink "$(basename "$1")") done REALPATH="$PWD/$(basename "$1")" cd "$OURPWD" echo "$REALPATH" } realpath "$@" 

Espero que pueda ser de alguna utilidad para alguien.

Estaba buscando una solución para usar en una secuencia de comandos de suministro del sistema, es decir, ejecutar antes de que Homebrew esté instalado. Al carecer de una solución adecuada, simplemente descargaría la tarea a un lenguaje multiplataforma, por ejemplo, Perl:

 script_abspath=$(perl -e 'use Cwd "abs_path"; print abs_path(@ARGV[0])' -- "$0") 

Más a menudo lo que realmente queremos es el directorio contenedor:

 here=$(perl -e 'use File::Basename; use Cwd "abs_path"; print dirname(abs_path(@ARGV[0]));' -- "$0") 

Use Python para obtenerlo

 #!/usr/bin/env python import os import sys print(os.path.realpath(sys.argv[1])) 

Una variante más amigable con la línea de comandos de la solución de Python:

 python -c "import os; print(os.path.realpath('$1'))" 

Dado que hay un camino real como otros han señalado:

 // realpath.c #include  #include  int main (int argc, char* argv[]) { if (argc > 1) { for (int argIter = 1; argIter < argc; ++argIter) { char *resolved_path_buffer = NULL; char *result = realpath(argv[argIter], resolved_path_buffer); puts(result); if (result != NULL) { free(result); } } } return 0; } 

Makefile:

 #Makefile OBJ = realpath.o %.o: %.c $(CC) -c -o $@ $< $(CFLAGS) realpath: $(OBJ) gcc -o $@ $^ $(CFLAGS) 

Luego, comstack con make y coloca un enlace suave con:
ln -s $(pwd)/realpath /usr/local/bin/realpath

Como puede ver arriba, hice una toma de esto hace unos 6 meses. Me olvidé por completo hasta que me encontré en la necesidad de algo similar otra vez. Estaba completamente sorprendido de ver qué tan rudimentario era; Hace casi un año que me enseño a progtwigr de forma bastante intensiva, pero a menudo siento que quizás no aprendí nada cuando las cosas están en su peor momento.

Quitaría la ‘solución’ anterior, pero realmente me gusta que sea un registro de cuánto he aprendido en los últimos meses.

Pero yo divago. Me senté y trabajé todo anoche. La explicación en los comentarios debería ser suficiente. Si desea realizar un seguimiento de la copia en la que continúo trabajando, puede seguir esta idea. Esto probablemente hace lo que necesitas.

 #!/bin/sh # dash bash ksh # !zsh (issues). G. Nixon, 12/2013. Public domain. ## 'linkread' or 'fullpath' or (you choose) is a little tool to recursively ## dereference symbolic links (ala 'readlink') until the originating file ## is found. This is effectively the same function provided in stdlib.h as ## 'realpath' and on the command line in GNU 'readlink -f'. ## Neither of these tools, however, are particularly accessible on the many ## systems that do not have the GNU implementation of readlink, nor ship ## with a system compiler (not to mention the requisite knowledge of C). ## This script is written with portability and (to the extent possible, speed) ## in mind, hence the use of printf for echo and case statements where they ## can be substituded for test, though I've had to scale back a bit on that. ## It is (to the best of my knowledge) written in standard POSIX shell, and ## has been tested with bash-as-bin-sh, dash, and ksh93. zsh seems to have ## issues with it, though I'm not sure why; so probably best to avoid for now. ## Particularly useful (in fact, the reason I wrote this) is the fact that ## it can be used within a shell script to find the path of the script itself. ## (I am sure the shell knows this already; but most likely for the sake of ## security it is not made readily available. The implementation of "$0" ## specificies that the $0 must be the location of **last** symbolic link in ## a chain, or wherever it resides in the path.) This can be used for some ## ...interesting things, like self-duplicating and self-modifiying scripts. ## Currently supported are three errors: whether the file specified exists ## (ala ENOENT), whether its target exists/is accessible; and the special ## case of when a sybolic link references itself "foo -> foo": a common error ## for beginners, since 'ln' does not produce an error if the order of link ## and target are reversed on the command line. (See POSIX signal ELOOP.) ## It would probably be rather simple to write to use this as a basis for ## a pure shell implementation of the 'symlinks' util included with Linux. ## As an aside, the amount of code below **completely** belies the amount ## effort it took to get this right -- but I guess that's coding for you. ##===-------------------------------------------------------------------===## for argv; do :; done # Last parameter on command line, for options parsing. ## Error messages. Use functions so that we can sub in when the error occurs. recurses(){ printf "Self-referential:\n\t$argv ->\n\t$argv\n" ;} dangling(){ printf "Broken symlink:\n\t$argv ->\n\t"$(readlink "$argv")"\n" ;} errnoent(){ printf "No such file: "$@"\n" ;} # Borrow a horrible signal name. # Probably best not to install as 'pathfull', if you can avoid it. pathfull(){ cd "$(dirname "$@")"; link="$(readlink "$(basename "$@")")" ## 'test and 'ls' report different status for bad symlinks, so we use this. if [ ! -e "$@" ]; then if $(ls -d "$@" 2>/dev/null) 2>/dev/null; then errnoent 1>&2; exit 1; elif [ ! -e "$@" -a "$link" = "$@" ]; then recurses 1>&2; exit 1; elif [ ! -e "$@" ] && [ ! -z "$link" ]; then dangling 1>&2; exit 1; fi fi ## Not a link, but there might be one in the path, so 'cd' and 'pwd'. if [ -z "$link" ]; then if [ "$(dirname "$@" | cut -c1)" = '/' ]; then printf "$@\n"; exit 0; else printf "$(pwd)/$(basename "$@")\n"; fi; exit 0 fi ## Walk the symlinks back to the origin. Calls itself recursivly as needed. while [ "$link" ]; do cd "$(dirname "$link")"; newlink="$(readlink "$(basename "$link")")" case "$newlink" in "$link") dangling 1>&2 && exit 1 ;; '') printf "$(pwd)/$(basename "$link")\n"; exit 0 ;; *) link="$newlink" && pathfull "$link" ;; esac done printf "$(pwd)/$(basename "$newlink")\n" } ## Demo. Install somewhere deep in the filesystem, then symlink somewhere ## else, symlink again (maybe with a different name) elsewhere, and link ## back into the directory you started in (or something.) The absolute path ## of the script will always be reported in the usage, along with "$0". if [ -z "$argv" ]; then scriptname="$(pathfull "$0")" # Yay ANSI l33t codes! Fancy. printf "\n\033[3mfrom/as: \033[4m$0\033[0m\n\n\033[1mUSAGE:\033[0m " printf "\033[4m$scriptname\033[24m [ link | file | dir ]\n\n " printf "Recursive readlink for the authoritative file, symlink after " printf "symlink.\n\n\n \033[4m$scriptname\033[24m\n\n " printf " From within an invocation of a script, locate the script's " printf "own file\n (no matter where it has been linked or " printf "from where it is being called).\n\n" else pathfull "$@" fi 

realpath para Mac OS X

 realpath() { path=`eval echo "$1"` folder=$(dirname "$path") echo $(cd "$folder"; pwd)/$(basename "$path"); } 

Ejemplo con una ruta relacionada:

 realpath "../scripts/test.sh" 

Ejemplo con la carpeta de inicio

 realpath "~/Test/../Test/scripts/test.sh" 

Eche un vistazo a esta pregunta. Encontré la respuesta más concisa.

obtener la ruta donde se encuentra un script de shell osx dentro del script … cuando el camino tiene espacio en blanco