cdes 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 bashmanual :
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 cdno 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 cdprograma 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 cdprograma de confianza o alguna otra cosa. Esa es una lata entera de gusanos.
O podría tener un cdprograma que haga que el chdirsistema 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
echoy testson utilidades con mandato POSIX ( /bin/echoy /bin/test). Sin embargo, casi todos los depósitos popular tiene una orden interna echoy test. Del mismo modo, killtambié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 PATHmientras 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 dashorigen, 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
evalcommandluego se usa findcommandpara 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.cmdes un struct( struct builtincmd), uno de cuyos miembros es un puntero de función, con una firma típica de main: (int, char **). La evalbltinfunción llama (dependiendo de si el evalcomando incorporado es el comando o no) evalcmdo 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 cdejecutable .
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 .
typecomando