¿Cómo hacer que un script que usa $0 funcione cuando está en $PATH?

¿Cómo hacer que un script que usa $0 funcione cuando está en $PATH?

Tengo un script (~/.../gremlin) para el cual creé un enlace suave:

ln -s ~/[...]/gremlin ~/sc/gremlin

~/sc/gremlines en $PATH.
Llamar al script directamente funciona.
Llamarlo a través del enlace no lo hace.
Se utiliza dirname $0para no recibir nada.

¿Hay alguna manera de hacer que esta configuración funcione sin cambiar el script y sin crear otro en lugar del enlace suave?

Así es como se usa $0:

case `uname` in
  CYGWIN*)
    CP=$( echo `dirname $0`/../lib/*.jar . | sed 's/ /;/g')
    ;;
  *)
    CP=$( echo `dirname $0`/../lib/*.jar . | sed 's/ /:/g')
esac

Respuesta1

Si el uso de dirname $0es un problema o no dependerá decómoesta usado. Sin más detalles, no podemos responder eso.

Si (a) el uso de dirname $0es un problema y (b) no puede cambiar el script, entonces la solución es reemplazar el enlace suave ~/sc/gremlincon un script:

#!/bin/sh
exec ~/../gremlin "$@"

De esta forma ~/../gremlinse ejecutará con un formato correcto $0.

El uso de execsignifica que el proceso que ejecuta el script ~/../gremlinreemplazará al proceso que ejecuta ~/sc/gremlin. Esto es más eficiente que mantener ambos procesos hasta que ~/../gremlinse completen.

Respuesta2

Si desea derivar el ~/...directorio desde $0, en lugar de hacerlo ~/scdesde el script, puede hacer:

Si es un zshguión:

#! /bin/zsh -
dir=$0:A:h

De lo contrario, y siempre que tenga un readlinkcomando que se comporte como el de GNU (algunos sistemas tienen un realpathcomando que puede usar en su lugar):

#! /bin/sh -
dir=$(dirname -- "$(readlink -f -- "$0")")

readlink -fy $0:Adarte elcanónicoruta del archivo, que es una ruta absoluta después de la resolución de todos los enlaces simbólicos en todos los componentes de la ruta.

Y luego:

set -- "$dir"/../lib/*.jar .
case $(uname) in
  CYGWIN*) IFS=';';;
  *)       IFS=:;;
esac
CP="$*"

O:

case $(uname) in
  CYGWIN*) sep=';';;
  *)       sep=:;;
esac
CP=$(printf "%s$sep" "$dir"/../lib/*.jar).

Respuesta3

Como señaló @john1024, el error tipográfico en la pregunta del OP puede ser el punto de la pregunta:

ln -s ~/.../gremlin ~/sc/gremlin

Si bien algunas aplicaciones respetan los puntos triples, los sistemas de archivos Unix no. Sucaparazónexpande la ~(tilde), no ln, entonces

    ln -s ~/../gremlin ~/sc/gremlin

expandiría el nombre de la ruta como se esperaba. Si el enlace ya existe, puede sobrescribirlo usando la -fopción. Sin embargo, si el destino es un archivo real, la -fopción sobrescribirá silenciosamente el archivo con un enlace simbólico. Es posible que desee utilizar la -iopción que al menos le indica que ya hay algo allí.

Si quieres validar el enlace (probar que apunta a un archivo), es útil la -Lopción de :ls

ls -lL ~/sc/gremlin

Si no es un archivo, ls(según la implementación) mostrará solo un lpara el tipo (el primer carácter de la lista), con signos de interrogación para los bits de permiso) o alguna otra indicación de que no apunta a un archivo real. (OSX simplemente se niega a mostrar nada en este caso, aunque cuenta el tamaño del enlace simbólico en el total).

Otras lecturas:

información relacionada