Como sospecha, el comportamiento exacto depende del shell, pero POSIX especifica un nivel básico de funcionalidad.
La búsqueda y ejecución de comandos para el lenguaje de comandos de shell estándar (que la mayoría de los shells implementan un superconjunto) tiene muchos casos, pero solo estamos interesados por el momento en el caso en que PATH
se usa. En ese caso:
se buscará el comando utilizando la variable de entorno PATH como se describe en Variables de entorno XBD
y
Si la búsqueda es exitosa:
[...]
el shell ejecuta la utilidad en un entorno de utilidad separado con acciones equivalentes a llamar a la execl()
función [...] con el argumento de ruta establecido en el nombre de ruta resultante de la búsqueda.
En el caso fallido, la ejecución falla y se devuelve un código de salida de 127 con un mensaje de error.
Este comportamiento es consistente con la execvp
función, en particular. Todas las exec*
funciones aceptan el nombre de archivo de un programa para ejecutar, una secuencia de argumentos (que será la argv
del programa) y quizás un conjunto de variables de entorno. Para las versiones que utilizan la PATH
búsqueda, POSIX define que :
El archivo de argumento se utiliza para construir un nombre de ruta que identifica el nuevo archivo de imagen de proceso, el [...] prefijo de ruta para este archivo se obtiene mediante una búsqueda de los directorios pasados como la variable de entorno RUTA
El comportamiento de PATH se define en otros lugares como:
Esta variable representará la secuencia de prefijos de ruta que ciertas funciones y utilidades aplican al buscar un archivo ejecutable conocido solo por un nombre de archivo. Los prefijos deben estar separados por un <colon> (':'). Cuando se aplica un prefijo de longitud distinta de cero a este nombre de archivo, se insertará una <barra inclinada> entre el prefijo y el nombre de archivo si el prefijo no termina en. Un prefijo de longitud cero es una característica heredada que indica el directorio de trabajo actual. Aparece como dos caracteres adyacentes ("::"), como un <colon> inicial que precede al resto de la lista, o como un <colon> al final del resto de la lista. Una aplicación estrictamente conforme utilizará un nombre de ruta real (como.) Para representar el directorio de trabajo actual en PATH.Se buscará en la lista de principio a fin, aplicando el nombre de archivo a cada prefijo, hasta que se encuentre un archivo ejecutable con el nombre especificado y los permisos de ejecución apropiados . Si el nombre de ruta que se busca contiene una <barra inclinada>, no se realizará la búsqueda a través de los prefijos de ruta. Si el nombre de ruta comienza con una <barra inclinada>, la ruta especificada se resuelve (consulte Resolución de nombre de ruta ). Si PATH no está establecido o está establecido en nulo, la búsqueda de ruta está definida por la implementación.
Eso es un poco denso, así que un resumen:
- Si el nombre del programa tiene un
/
(barra oblicua, U + 002F SOLIDUS), trátelo como una ruta de la manera habitual y omita el resto de este proceso. Para el shell, este caso técnicamente no surge (porque las reglas del shell ya lo habrán tratado).
- El valor de
PATH
se divide en partes en cada punto y luego cada componente se procesa de izquierda a derecha. Como un caso especial (histórico), un componente vacío de una variable no vacía se trata como .
(el directorio actual).
- Para cada componente, el nombre del programa se agrega al final con una unión
/
y se verifica la existencia de un archivo con ese nombre, y si existe uno, también se verifican los permisos válidos de ejecución (+ x). Si alguna de esas verificaciones falla, el proceso pasa al siguiente componente. De lo contrario, el comando se resuelve en esta ruta y se realiza la búsqueda.
- Si te quedas sin componentes, la búsqueda falla.
- Si no hay nada
PATH
o no existe, haga lo que quiera.
Los shells reales tendrán comandos incorporados, que se encuentran antes de esta búsqueda, y a menudo también alias y funciones. Aquellos con los que no interactúan PATH
. POSIX define algunos comportamientos en torno a ellos , y su shell puede tener mucho más.
Si bien es posible confiar en exec*
hacer la mayor parte de esto por usted, el shell en la práctica puede implementar esta búsqueda en sí misma, especialmente para fines de almacenamiento en caché, pero el comportamiento de la memoria caché vacía debería ser similar. Los proyectiles tienen una latitud bastante amplia aquí y tienen comportamientos sutilmente diferentes en los casos de esquina.
Como descubrió, Bash usa una tabla hash para recordar las rutas completas de los comandos que se han visto antes, y se puede acceder a esa tabla con la hash
función. La primera vez que ejecuta un comando, busca, y cuando se encuentra un resultado, se agrega a la tabla, por lo que no hay necesidad de molestarse en buscarlo la próxima vez que lo intente.
En zsh, por otro lado, PATH
generalmente se busca el valor completo cuando se inicia el shell. Una tabla de búsqueda se rellena previamente con todos los nombres de comandos descubiertos, por lo que las búsquedas en tiempo de ejecución generalmente no son necesarias (a menos que se agregue un nuevo comando). Puede notar que esto sucede cuando intenta completar con tabulación un comando que no existía antes.
Los shells muy livianos, como dash
, tienden a delegar la mayor cantidad de comportamiento posible a la biblioteca del sistema y no se molestan en recordar rutas de comandos pasadas.
PATH
entrebash
yzsh
me ayuda a resolver mi confusión!