En 1996 instalé la primera versión de GNU/Linux en mi PC, compilé un código en C y no pude ejecutarlo. No sabía el porqué. El fichero estaba ahí y al igual que en DOS con los ficheros de tipo exe parecía poder ejecutarse. Tiempo después me dijeron que debía escribir la ruta relativa o absoluta al fichero o agregar la ruta actual, el punto (.) dentro del PATH, ¿pero por qué?
Al principio me frustraba mucho el hecho de crear un script o un programa y tener que ejecutarlo como ./miprograma
en lugar de simplemente miprograma
. Llegué a agregar dentro de mi .bashrc
esta simple línea:
export PATH="$PATH:."
Para asegurarme de tener siempre la ruta local disponible y no tener que emplear una ruta relativa cuando el fichero a ejecutar se encontraba en la ruta actual. Pero incluso me llamó mucho más la atención cuando el script o el binario a ejecutar se encontraba en otro subdirectorio y veía a compañeros ejecutar:
$ ./target/miprograma
En lugar de tan solo escribir:
$ target/miprograma
Parecía que la combinación inicial ./
hacía pensar a muchas personas que si el binario se encontraba fuera de las rutas del PATH, entonces debía ser llamado siempre con esa combinación inicial.
Para profundizar un poco más en todo esto primero dejaremos claros algunos conceptos.
Programas, Binarios y Scripts
En todos los sistemas operativos nos encontramos con directorios y subdirectorios (o carpetas y subcarpetas), donde introducimos nuestros ficheros (o archivos). Estos archivos, dependiendo si tratamos con un sistema operativo Windows o tipo Unix, deben:
-
en Windows tener una extensión concreta como
.exe
principalmente, aunque también podemos hacer scripts con extensiones como.bat
o.cmd
. La extensión determina si se puede ejecutar o no. - en sistemas tipo Unix (GNU/Linux, macOS o FreeBSD entre otros) los ficheros deben tener un permiso de ejecución que permita al usuario ejecutar ese binario o script. La extensión no es importante.
Un fichero binario normalmente será un archivo generado por un compilador que permite ser ejecutado en el sistema operativo. Por tanto deberemos poder ejecutarlo sin problemas.
Un script será un archivo de texto plano que contenga instrucciones a ser interpretadas por un intérprete de comandos como puede ser bash
, zsh
, csh
, powershell
, cmd.exe
o [fish][FISH] entre otros.
Rutas relativas y rutas absolutas
Ejecutando una consola o empleando Finder en macOS, o el Explorer en Windows, o cualquier otro visor de ficheros tendremos siempre una ruta donde nos encontramos. En sistemas Unix podemos emplear el comando pwd
para obtener la ruta absoluta donde nos encontramos. En los gestores de ficheros normalmente aparecerá en la barra de direcciones la ruta absoluta donde nos encontramos.
Estas rutas mostradas están en dirección absoluta, según el sistema operativo la ruta puede ser
-
en Windows absoluta cuando comienza por la unidad seguida de una barra invertida (\), algo como
C:\WIN\SYSTEM32
nos indica la ruta absoluta para el directorioSYSTEM32
. La ruta relativa, en caso de encontrarnos en la unidadC:
podría serWIN\SYSTEM32
o si estamos enWIN
puede ser simplementeSYSTEM32
. -
en sistemas tipo Unix absoluta es cuando comienza por una barra inclinada (/), algo como
/usr/local/bin
nos indica la ruta absoluta para el directoriobin
. La ruta relativa, en caso de encontrarnos en/
podría serusr/local/bin
o si estamos en/usr
puede serlocal/bin
o si estamos en/usr/local
puede ser simplementebin
.
Ejecutando programas
Entonces, hemos dicho que para ejecutar un programa especificando solo su nombre en sistemas tipo Unix deben cumplirse la premisa de estar localizado a través de alguna de las rutas disponibles en la variable de entorno PATH
:
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin
Esto quiere decir que si escribo en la shell el comando ls
, este será buscado en las rutas:
-
/usr/local/bin
-
/usr/bin
-
/bin
-
/usr/sbin
-
/sbin
-
/opt/X11/bin
Y en ese orden. En este caso el fichero binario ls
con permisos de ejecución se encuentra en la ruta /bin/ls
, podemos verlo aquí:
$ whereis ls
/bin/ls
Por lo que buscó antes en dos sitios. La única forma de evitar la búsqueda es indicar una ruta relativa o absoluta. Eso quiere decir que si escribimos /sbin/ls
obtendremos un error porque intenta ejecutar un fichero que no existe en la ruta proporcionada.
¿Qué hacemos por tanto si queremos ejecutar un script que acabamos de escribir en la ruta donde nos encontramos?
Pues tenemos dos opciones.
Directorio Binario Propio
Es normal si como usuario en sistemas tipo Unix generas muchos scripts, para poder llamarlos de forma rápida estés en la ruta que estés, te creas un directorio que casa normalmente con ~/bin
o $HOME/bin
. Siendo ~
un símbolo especial para indicar tu directorio personal como usuario.
Esto suele ser fácil porque los shells proporcionan ficheros de inicio, normalmente ~/.bashrc
, o ~/.zshrc
, o ~/.bash_profile
, ... según la shell que emplees y el sistema operativo deberás buscar el fichero que corresponda. En ese fichero puedes modificar la variable PATH
para cada vez que entres:
export PATH="$PATH:$HOME/bin"
En consolas como fish
tan solo habría que crear un fichero:
$ echo 'set -gxa PATH ~/bin' >> ~/.config/fish/conf.d/mybin.fish
De esta forma al acceder a la consola la siguiente vez se habrá actualizado nuestro PATH
y ahora ya sí podremos emplear cualquier script dentro de ese directorio sin necesidad de agregar siempre la ruta relativa.
Usar el infame ./
Sí. Otra forma es simular una ruta relativa hacia el propio directorio. Esto es posible gracias a los directorios especiales punto (.) y dos puntos (..). En sistemas Windows simplemente haciendo dir
podrás verlos en cmd
. En sistemas tipo Unix debemos ejecutar:
$ ls -a
. .. .bashrc bin prueba.sh
El directorio punto (.) es un enlace al directorio donde nos encontramos. Es recursivo. Si hacemos ls
o ls .
o ls ./.
o ls ././.
y así hasta el infinito siempre obtendremos el mismo resultado. No obstante el directorio (..) es un enlace al directorio anterior o padre. Esto nos permite realizar acciones como cd ..
para llevarnos al directorio anterior.
Entonces, si necesitamos ejecutar el script prueba.sh
del directorio actual, deberemos hacer:
$ ./prueba.sh
Si por contra hemos cambiado el directorio actual:
$ cd bin
$ ../prueba.sh
Esta vez la ruta relativa la construimos con el directorio de dos puntos (..) para referenciar al directorio padre donde se encuentra el script.
¿Por qué no agregamos el .
en el PATH
?
En principio, dicen que por problemas de seguridad. Porque si te cambias a un directorio de un usuario y ejecutas ls
para ver su contenido y sucede que hay un binario ls
malicioso, es dañino. Pero, la verdad es que esta teoría es fácil de desmontar porque si configuramos:
export PATH="$PATH:."
La búsqueda de la ruta actual la estamos anexando al final. Por lo tanto, debe encontrar siempre ls
en su ruta original antes que en la ruta donde está el usuario en ese momento.
Realmente no se conoce el motivo que llevó a realizar este cambio en la versión 3 de Unix, donde rompieron con la herencia de Multics y en lugar de situar los scripts y programas dentro de /bin
y posteriormente además /usr/bin
cuando las limitaciones del momento les hicieron quedarse sin espacio, decidieron dejar esta búsqueda configurable por el usuario a través de la variable de entorno PATH
.
Conclusiones
No tiene sentido actualmente no agregar el punto (.) AL FINAL de nuestra variable de entorno PATH
según mi opinión. Al igual que no tiene sentido que cuando ejecutamos un binario o script en una ruta relativa antepongamos el prefijo ./
por creer que tiene un significado especial. Creo que son dejes que habrá que ir subsanando poco a poco.
¿Y tú? ¿Empleas el infame prefijo ./
para todo lo que ejecutas de forma local? ¿Sabías que podías eliminar su uso? ¿Qué otros usos extraños encuentras en Windows o sistemas Unix referentes a ejecución o uso de ficheros? ¡Déjanos tu comentario!