your the omf know how current check macos freebsd sh

macos - the - ¿Cómo puedo obtener el comportamiento de readlink-f de GNU en una Mac?



how to know the shell in linux (20)

  1. Instalar homebrew
  2. Ejecutar "brew install coreutils"
  3. Ejecutar "greadlink -f ruta"

greadlink es el enlace de lectura gnu que implementa -f. Puedes usar macports u otros también, prefiero homebrew.

En Linux, la utilidad de enlace de readlink acepta una opción -f que sigue a enlaces adicionales. Esto no parece funcionar en Mac y posiblemente en sistemas basados ​​en BSD. ¿Cuál sería el equivalente?

Aquí hay algo de información de depuración:

$ which readlink; readlink -f /usr/bin/readlink readlink: illegal option -f usage: readlink [-n] [file ...]


Aquí hay una función de shell portátil que debería funcionar en CUALQUIER shell comparable de Bourne. Se resolverá la puntuación relativa de la ruta ".. o". y desreferencia enlaces simbólicos.

Si, por alguna razón, no tiene un comando realpath (1), o enlace de lectura (1), puede tener un alias.

which realpath || alias realpath=''real_path''

Disfrutar:

real_path () { OIFS=$IFS IFS=''/'' for I in $1 do # Resolve relative path punctuation. if [ "$I" = "." ] || [ -z "$I" ] then continue elif [ "$I" = ".." ] then FOO="${FOO%%/${FOO##*/}}" continue else FOO="${FOO}/${I}" fi ## Resolve symbolic links if [ -h "$FOO" ] then IFS=$OIFS set `ls -l "$FOO"` while shift ; do if [ "$1" = "->" ] then FOO=$2 shift $# break fi done IFS=''/'' fi done IFS=$OIFS echo "$FOO" }

También, en caso de que a alguien le interese aquí, es cómo implementar basename y dirname en código de shell 100% puro:

## http://www.opengroup.org/onlinepubs/000095399/functions/dirname.html # the dir name excludes the least portion behind the last slash. dir_name () { echo "${1%/*}" } ## http://www.opengroup.org/onlinepubs/000095399/functions/basename.html # the base name excludes the greatest portion in front of the last slash. base_name () { echo "${1##*/}" }

Puede encontrar la versión actualizada de este código de shell en mi sitio de Google: http://sites.google.com/site/jdisnard/realpath

EDITAR: Este código se otorga bajo los términos de la licencia de 2 cláusulas (estilo freeBSD). Puede encontrar una copia de la licencia siguiendo el hipervínculo anterior a mi sitio.


Escribí una utilidad realpath para OS X que puede proporcionar los mismos resultados que readlink -f .


Aquí hay un ejemplo:

(jalcazar@mac tmp)$ ls -l a lrwxrwxrwx 1 jalcazar jalcazar 11 8月 25 19:29 a -> /etc/passwd (jalcazar@mac tmp)$ realpath a /etc/passwd


Si está utilizando MacPorts, puede instalarlo con el siguiente comando: sudo port selfupdate && sudo port install realpath .


Esto es lo que uso:

stat -f %N $your_path


Hice un script llamado realpath personalmente que se parece a algo como:

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


La forma más fácil de resolver este problema y habilitar la funcionalidad de readlink en Mac con Homebrew instalado o FreeBSD es instalar el paquete ''coreutils''. También puede ser necesario en ciertas distribuciones de Linux y otros sistemas operativos POSIX.

Por ejemplo, en FreeBSD 11, instalé invocando:

# pkg install coreutils

En MacOS con Homebrew, el comando sería:

$ brew install coreutils

No estoy seguro de por qué las otras respuestas son tan complicadas, eso es todo lo que hay que hacer. Los archivos no están en un lugar diferente, simplemente no están instalados todavía.


La respuesta de @Keith Smith da un bucle infinito.

Aquí está mi respuesta, la cual uso solo en SunOS (SunOS pierde tanto los comandos POSIX y GNU).

Es un archivo de secuencia de comandos que debe colocar en uno de sus directorios de $ PATH:

#!/bin/sh ! (($#)) && echo -e "ERROR: readlink <link to analyze>" 1>&2 && exit 99 link="$1" while [ -L "$link" ]; do lastLink="$link" link=$(/bin/ls -ldq "$link") link="${link##* -> }" link=$(realpath "$link") [ "$link" == "$lastlink" ] && echo -e "ERROR: link loop detected on $link" 1>&2 && break done echo "$link"


Las rutas a readlink son diferentes entre mi sistema y el tuyo. Por favor, intente especificar la ruta completa:

/sw/sbin/readlink -f


MacPorts y Homebrew proporcionan un paquete coreutils que contiene greadlink ( greadlink GNU). Crédito para Michael Kallweitt puesto en mackb.com.

brew install coreutils greadlink -f file.txt


Mejor tarde que nunca, supongo. Estaba motivado a desarrollar esto específicamente porque mis scripts de Fedora no estaban trabajando en la Mac. El problema son las dependencias y Bash. Las Mac no las tienen, o si las tienen, a menudo están en otro lugar (otra ruta). La manipulación de la ruta de dependencia en un script Bash multiplataforma es, en el mejor de los casos, un dolor de cabeza y, en el peor, un riesgo para la seguridad, por lo que es mejor evitar su uso, si es posible.

La función get_realpath () a continuación es simple, centrada en Bash, y no se requieren dependencias. Yo solo uso Bash builtins echo y cd . También es bastante seguro, ya que todo se prueba en cada etapa del camino y devuelve condiciones de error.

Si no desea seguir los enlaces simbólicos, coloque set -P al principio del script, pero de lo contrario, cd debería resolver los enlaces simbólicos de forma predeterminada. Se ha probado con argumentos de archivo que son {absolutos | pariente enlace simbólico | local} y devuelve la ruta absoluta al archivo. Hasta ahora no hemos tenido ningún problema con ello.

function get_realpath() { if [[ -f "$1" ]] then # file *must* exist if cd "$(echo "${1%/*}")" &>/dev/null then # file *may* not be local # exception is ./file.ext # try ''cd .; cd -;'' *works!* local tmppwd="$PWD" cd - &>/dev/null else # file *must* be local local tmppwd="$PWD" fi else # file *cannot* exist return 1 # failure fi # reassemble realpath echo "$tmppwd"/"${1##*/}" return 0 # success }

Puede combinar esto con otras funciones get_dirname, get_filename, get_stemname y validate_path. Estos se pueden encontrar en nuestro repositorio de GitHub como realpath-lib (divulgación completa: este es nuestro producto, pero lo ofrecemos de forma gratuita a la comunidad sin ninguna restricción). También podría servir como una herramienta de instrucción, está bien documentada.

Hemos hecho todo lo posible para aplicar las llamadas prácticas ''Bash modernas'', pero Bash es un tema importante y estoy seguro de que siempre habrá espacio para mejorar. Requiere Bash 4+, pero se podría hacer que funcione con versiones anteriores si aún están disponibles.


Odio acumularme con otra implementación más, pero necesitaba a) una implementación de shell pura y portátil, yb) cobertura de prueba unitaria , ya que la cantidad de casos de borde para algo como esto no es trivial .

Ver mi proyecto en Github para pruebas y código completo. Lo que sigue es una sinopsis de la implementación:

Como Keith Smith señala astutamente, readlink -f hace dos cosas: 1) resuelve enlaces simbólicos recursivamente, y 2) canonicaliza el resultado, por lo tanto:

realpath() { canonicalize_path "$(resolve_symlinks "$1")" }

Primero, la implementación del programa de enlace de enlaces:

resolve_symlinks() { local dir_context path path=$(readlink -- "$1") if [ $? -eq 0 ]; then dir_context=$(dirname -- "$1") resolve_symlinks "$(_prepend_path_if_relative "$dir_context" "$path")" else printf ''%s/n'' "$1" fi } _prepend_path_if_relative() { case "$2" in /* ) printf ''%s/n'' "$2" ;; * ) printf ''%s/n'' "$1/$2" ;; esac }

Tenga en cuenta que esta es una versión ligeramente simplificada de la implementación completa . La implementación completa agrega una pequeña comprobación de los ciclos de enlaces simbólicos , así como un masaje de la salida un poco.

Finalmente, la función para canonicalizar un camino:

canonicalize_path() { if [ -d "$1" ]; then _canonicalize_dir_path "$1" else _canonicalize_file_path "$1" fi } _canonicalize_dir_path() { (cd "$1" 2>/dev/null && pwd -P) } _canonicalize_file_path() { local dir file dir=$(dirname -- "$1") file=$(basename -- "$1") (cd "$dir" 2>/dev/null && printf ''%s/%s/n'' "$(pwd -P)" "$file") }

Eso es, más o menos. Lo suficientemente simple como para pegarlo en su script, pero lo suficientemente complicado como para estar loco y confiar en cualquier código que no tenga pruebas unitarias para sus casos de uso.


Perl tiene una función de enlace de lectura (por ejemplo, ¿Cómo copio enlaces simbólicos en Perl? ). Esto funciona en la mayoría de las plataformas, incluido OS X:

perl -e "print readlink ''/path/to/link''"

Por ejemplo:

$ mkdir -p a/b/c $ ln -s a/b/c x $ perl -e "print readlink ''x''" a/b/c


Puede estar interesado en realpath(3) , o en os.path.realpath de Python. Los dos no son exactamente iguales; la llamada a la biblioteca de C requiere que existan componentes de ruta intermedios, mientras que la versión de Python no existe.

$ pwd /tmp/foo $ ls -l total 16 -rw-r--r-- 1 miles wheel 0 Jul 11 21:08 a lrwxr-xr-x 1 miles wheel 1 Jul 11 20:49 b -> a lrwxr-xr-x 1 miles wheel 1 Jul 11 20:49 c -> b $ python -c ''import os,sys;print(os.path.realpath(sys.argv[1]))'' c /private/tmp/foo/a

Sé que dijiste que preferirías algo más ligero que otro lenguaje de scripting, pero en caso de que compilar un binario sea insoportable, puedes usar Python y ctypes (disponibles en Mac OS X 10.5) para ajustar la llamada de la biblioteca:

#!/usr/bin/python import ctypes, sys libc = ctypes.CDLL(''libc.dylib'') libc.realpath.restype = ctypes.c_char_p libc.__error.restype = ctypes.POINTER(ctypes.c_int) libc.strerror.restype = ctypes.c_char_p def realpath(path): buffer = ctypes.create_string_buffer(1024) # PATH_MAX if libc.realpath(path, buffer): return buffer.value else: errno = libc.__error().contents.value raise OSError(errno, "%s: %s" % (libc.strerror(errno), buffer.value)) if __name__ == ''__main__'': print realpath(sys.argv[1])

Irónicamente, la versión C de este script debería ser más corta. :)


Que hay de esto

function readlink() { DIR=$(echo "${1%/*}") (cd "$DIR" && echo "$(pwd -P)") }


Un simple one-liner en perl que seguramente funcionará en casi todas partes sin dependencias externas:

perl -MCwd -e ''print Cwd::abs_path shift'' ~/non-absolute/file

Dereference symlinks.

El uso en un script podría ser así:

readlinkf(){ perl -MCwd -e ''print Cwd::abs_path shift'' "$1";} ABSPATH="$(readlinkf ./non-absolute/file)"


Verdaderamente la plataforma independiente sería también este R-onliner

readlink(){ RScript -e "cat(normalizePath(commandArgs(T)[1]))" "$1";}

Para imitar realmente el enlace de readlink -f <path> , sería necesario usar $ 2 en lugar de $ 1.


Ya hay muchas respuestas, pero ninguna funcionó para mí ... Así que esto es lo que estoy usando ahora.

readlink_f() { local target="$1" [ -f "$target" ] || return 1 #no nofile while [ -L "$target" ]; do target="$(readlink "$target")" done echo "$(cd "$(dirname "$target")"; pwd -P)/$target" }


FreeBSD y OSX tienen una versión de stat derivada de NetBSD.

Puede ajustar la salida con modificadores de formato (consulte las páginas de manual en los enlaces anteriores).

% cd /service % ls -tal drwxr-xr-x 22 root wheel 27 Aug 25 10:41 .. drwx------ 3 root wheel 8 Jun 30 13:59 .s6-svscan drwxr-xr-x 3 root wheel 5 Jun 30 13:34 . lrwxr-xr-x 1 root wheel 30 Dec 13 2013 clockspeed-adjust -> /var/service/clockspeed-adjust lrwxr-xr-x 1 root wheel 29 Dec 13 2013 clockspeed-speed -> /var/service/clockspeed-speed % stat -f%R clockspeed-adjust /var/service/clockspeed-adjust % stat -f%Y clockspeed-adjust /var/service/clockspeed-adjust

Algunas versiones de OS X de stat pueden carecer de la opción -f%R para los formatos. En este caso -stat -f%Y puede ser suficiente. La opción -f%Y mostrará el objetivo de un enlace simbólico, mientras que -f%R muestra la ruta de acceso absoluta correspondiente al archivo.

EDITAR:

Si puede usar Perl (Darwin / OS X viene instalado con versiones recientes de perl ), entonces:

perl -MCwd=abs_path -le ''print abs_path readlink(shift);'' linkedfile.txt

trabajará.


readlink -f hace dos cosas:

  1. Recorre una secuencia de enlaces simbólicos hasta que encuentra un archivo real.
  2. Devuelve el nombre canonizado de ese archivo, es decir, su ruta de acceso absoluta.

Si lo desea, simplemente puede crear un script de shell que use el comportamiento de vainilla readlink para lograr lo mismo. Aquí hay un ejemplo. Obviamente, puede insertar esto en su propio script donde le gustaría llamar a readlink -f

#!/bin/sh TARGET_FILE=$1 cd `dirname $TARGET_FILE` TARGET_FILE=`basename $TARGET_FILE` # Iterate down a (possible) chain of symlinks while [ -L "$TARGET_FILE" ] do TARGET_FILE=`readlink $TARGET_FILE` cd `dirname $TARGET_FILE` TARGET_FILE=`basename $TARGET_FILE` done # Compute the canonicalized name by finding the physical path # for the directory we''re in and appending the target file. PHYS_DIR=`pwd -P` RESULT=$PHYS_DIR/$TARGET_FILE echo $RESULT

Tenga en cuenta que esto no incluye ningún manejo de errores. De particular importancia, no detecta ciclos de enlaces simbólicos. Una forma sencilla de hacer esto sería contar la cantidad de veces que recorre el ciclo y fallará si alcanza un número improbable, como 1,000.

EDITADO para usar pwd -P lugar de $PWD .

Tenga en cuenta que esta secuencia de comandos espera ser llamada como ./script_name filename , no -f , cambie de $1 a $2 si desea poder usar con -f filename como GNU readlink.


Comenzar actualización

Este es un problema tan frecuente que hemos reunido una biblioteca de Bash 4 para uso libre (licencia MIT) llamada realpath-lib . Está diseñado para emular readlink -f de manera predeterminada e incluye dos suites de prueba para verificar (1) que funciona para un sistema Unix determinado y (2) contra readlink -f si está instalado (pero no es necesario). Además, puede utilizarse para investigar, identificar y desenrollar enlaces simbólicos profundos y rotos, así que puede ser una herramienta útil para diagnosticar problemas de archivos y directorios físicos o simbólicos profundamente anidados. Se puede encontrar en github.com o bitbucket.org .

Actualización final

Otra solución muy compacta y eficiente que no se basa en nada más que Bash es:

function get_realpath() { [[ ! -f "$1" ]] && return 1 # failure : file does not exist. [[ -n "$no_symlinks" ]] && local pwdp=''pwd -P'' || local pwdp=''pwd'' # do symlinks. echo "$( cd "$( echo "${1%/*}" )" 2>/dev/null; $pwdp )"/"${1##*/}" # echo result. return 0 # success }

Esto también incluye una configuración de entorno no_symlinks que proporciona la capacidad de resolver enlaces simbólicos al sistema físico. Siempre que no_symlinks esté configurado en algo, es decir, no_symlinks=''on'' entonces los enlaces simbólicos se resolverán en el sistema físico. De lo contrario, se aplicarán (la configuración predeterminada).

Esto debería funcionar en cualquier sistema que proporcione Bash y devolverá un código de salida compatible con Bash para fines de prueba.