cd
es un shell incorporado ordenado por POSIX :
Si un comando simple da como resultado un nombre de comando y una lista opcional de argumentos, se realizarán las siguientes acciones:
- Si el nombre del comando no contiene barras, se producirá el primer paso exitoso en la siguiente secuencia:
...
- Si el nombre del comando coincide con el nombre de una utilidad que figura en la siguiente tabla, se invocará esa utilidad.
...
cd
...
- De lo contrario, se buscará el comando utilizando la RUTA ...
Si bien esto no dice explícitamente que tiene que ser incorporado, la especificación continúa diciendo, en la descripción decd
:
Dado que cd afecta el entorno actual de ejecución del shell, siempre se proporciona como un shell integrado normal.
Del bash
manual :
Los siguientes comandos integrados de shell se heredan de Bourne Shell. Estos comandos se implementan según lo especificado por el estándar POSIX.
...
cd
cd [-L|[-P [-e]]] [directory]
Supongo que se podría pensar en una arquitectura donde cd
no tiene que ser un edificio. Sin embargo, tienes que ver lo que implica un incorporado. Si escribe un código especial en el shell para hacer algo para un comando, se está acercando a tener un builtin incorporado. Cuanto más lo hagas, mejor será simplemente tener un incorporado.
Por ejemplo, podría hacer que el shell tenga IPC para comunicarse con subprocesos, y habría un cd
programa que verificaría la existencia del directorio y si tiene permiso para acceder y luego se comunica con el shell para indicarle que cambie su directorio. Sin embargo, deberá verificar si el proceso de comunicación con usted es un niño (o hacer un medio especial de comunicación solo con los niños, como un descriptor de archivo especial, memoria compartida, etc.), y si el proceso es realmente ejecutando el cd
programa de confianza o alguna otra cosa. Esa es una lata entera de gusanos.
O podría tener un cd
programa que haga que el chdir
sistema llame y comience un nuevo shell con todas las variables de entorno actuales aplicadas al nuevo shell, y luego mate su shell principal (de alguna manera) cuando termine. 1
Peor aún, incluso podría tener un sistema en el que un proceso pueda alterar los entornos de otros procesos (creo que técnicamente puede hacerlo con depuradores). Sin embargo, dicho sistema sería muy, muy vulnerable.
Te encontrarás agregando más y más código para asegurar tales métodos, y es considerablemente más simple simplemente hacer que esté incorporado.
Que algo sea un ejecutable no evita que sea un archivo incorporado. Caso en punto:
echo
y test
echo
y test
son utilidades con mandato POSIX ( /bin/echo
y /bin/test
). Sin embargo, casi todos los depósitos popular tiene una orden interna echo
y test
. Del mismo modo, kill
también está incorporado que está disponible como un programa. Otros incluyen:
sleep
(no tan común)
time
false
true
printf
Sin embargo, hay algunos casos en que un comando no puede ser otra cosa que un builtin incorporado. Uno de esos es cd
. Por lo general, si no se especifica la ruta completa y el nombre del comando coincide con el de un builtin incorporado, se llama a una función adecuada para ese comando. Dependiendo de la shell, el comportamiento del builtin y el del ejecutable puede diferir (esto es particularmente un problema paraecho
, que tiene comportamientos muy diferentes . Si desea estar seguro del comportamiento, es preferible llamar al ejecutable usando el ruta completa y establecer variables como POSIXLY_CORRECT
(incluso entonces no hay garantía real).
Técnicamente, no hay nada que le impida proporcionar un sistema operativo que también sea un shell y que tenga todos los comandos como incorporado. Cerca de este extremo se encuentra el BusyBox monolítico . BusyBox es un binario único que (según el nombre con el que se llama) puede comportarse como cualquiera de los más de 240 programas , incluido un Shell de Almquist ( ash
). Si desarma PATH
mientras ejecuta BusyBox ash
, los programas disponibles en BusyBox aún estarán accesibles para usted sin especificar a PATH
. Se acercan a ser construcciones de conchas, excepto que la concha en sí es una especie de construcción para BusyBox.
Si observa el dash
origen, el hilo de ejecución es algo así (por supuesto, con funciones adicionales involucradas cuando se utilizan tuberías y otras cosas):
main
→ cmdloop
→ evaltree
→evalcommand
evalcommand
luego se usa findcommand
para determinar cuál es el comando. Si es una construcción, entonces :
case CMDBUILTIN:
if (spclbltin > 0 || argc == 0) {
poplocalvars(1);
if (execcmd && argc > 1)
listsetvar(varlist.list, VEXPORT);
}
if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
if (exception == EXERROR && spclbltin <= 0) {
FORCEINTON;
break;
cmdentry.u.cmd
es un struct
( struct builtincmd
), uno de cuyos miembros es un puntero de función, con una firma típica de main
: (int, char **)
. La evalbltin
función llama (dependiendo de si el eval
comando incorporado es el comando o no) evalcmd
o este puntero de función. Las funciones reales se definen en varios archivos de origen. echo
, por ejemplo, es :
int
echocmd(int argc, char **argv)
{
int nonl;
nonl = *++argv ? equal(*argv, "-n") : 0;
argv += nonl;
do {
int c;
if (likely(*argv))
nonl += print_escape_str("%s", NULL, NULL, *argv++);
if (nonl > 0)
break;
c = *argv ? ' ' : '\n';
out1c(c);
} while (*argv);
return 0;
}
Todos los enlaces al código fuente en esta sección están basados en números de línea, por lo que pueden cambiar sin previo aviso.
1 Los sistemas POSIX tienen un cd
ejecutable .
Nota al margen:
Hay muchas publicaciones excelentes en Unix y Linux que se ocupan del comportamiento de shell. En particular:
Si no ha notado un patrón en las preguntas enumeradas hasta ahora, casi todas ellas involucran a Stéphane Chazelas .
type
comando