¿Por qué "ls" requiere un proceso separado para ejecutarse?

14

¿Por qué lsrequiere un proceso separado para su ejecución? Sé la razón por la cual los comandos como cdno se pueden ejecutar mediante un mecanismo de bifurcación, pero ¿hay algún daño si lsse ejecuta sin bifurcación?

crisron
fuente
1
Aunque lses un programa externo, echo *o echo * .*(dependiendo de las opciones de shell) hace un trabajo bastante bueno de listar archivos sin bifurcación.
gerrit
Esto es aún mejor: printf "% s \ n" *
Costa
Nota de diversidad de Shell: tcsh tiene un incorporado ls-Fque actúa como ls -F. Está ahí para la eficiencia. Siempre obtienes lo -Fque suele ser una buena idea. Si especifica alguna otra opción, se dirige al comando externo.

Respuestas:

18

La respuesta es más o menos que lses un ejecutable externo. Puede ver su ubicación ejecutando type -p ls.

¿Por qué no está lsintegrado en la carcasa, entonces? Bueno, ¿por qué debería ser? El trabajo de un shell no es abarcar todos los comandos disponibles, sino proporcionar un entorno capaz de ejecutarlos. Algunos proyectiles modernos tienen echo, printfy su tipo de construcción, que técnicamente no tienen que ser construidos, pero están hechos por razones de rendimiento cuando se ejecutan repetidamente (principalmente en bucles estrechos). Sin hacerlos incorporados, el shell tendría que bifurcarse y ejecutar un nuevo proceso para cada llamada, que podría ser extremadamente lento.

Por lo menos, ejecutar ls, un ejecutable externo, requiere ejecutar una de la familia de llamadas de sistema ejecutivas. Usted podría hacer esto sin que se bifurcan, pero sería reemplazar la corteza primaria que está utilizando. Puede ver lo que sucede en esa instancia haciendo lo siguiente:

exec ls; echo "this never gets printed"

Dado que la imagen de proceso de su shell se reemplaza, el shell actual ya no es accesible después de hacer esto. Para que el shell pueda continuar ejecutándose después de ejecutar ls, el comando tendría que estar integrado en el shell.

La bifurcación permite reemplazar un proceso que no es su shell principal, lo que significa que puede continuar ejecutando su shell después.

Chris Down
fuente
1
Creo que está preguntando por qué ls (1) no es una característica integrada de los shells, que alguien necesitaría explicar cómo los diferentes proveedores tienen diferentes opciones para ls (1) y pueden consultar diferentes cosas del sistema de archivos, etc. Y también los altibajos, y en su mayoría los inconvenientes de tenerlo 'construido' en el caparazón.
llua
@llua he añadido algo de información al respecto, y los casos de excepción de echo, printf, etc.
Chris abajo
No siempre está claro por qué algunas cosas son incorporadas y otras no. Por ejemplo, ¿por qué cdno es un ejecutable externo?
Faheem Mitha
@FaheemMitha No es una externa cdejecutable en los sistemas operativos compatibles con POSIX ( ver aquí ). Sin embargo, si desea realmente chdir () en el proceso actual, debe tenerlo integrado en el shell.
Chris Down
se ha convertido en un hábito por qué lses externo, pero también se puede implementar en un shell. Ver busybox.
15

El Manual de referencia de Bash dice:

Los comandos incorporados son necesarios para implementar funcionalidades imposibles o inconvenientes de obtener con utilidades separadas.

Es decir, los shells están diseñados para incluir solo comandos integrados si:

  1. Requerido por el estándar POSIX
  2. Comandos que requieren acceso al shell en sí, como los controles integrados del trabajo
  3. Comandos que son muy simples, no dependen del sistema operativo y aumentan la eficiencia de ejecución cuando se implementan como incorporados, como printf

El lscomando no se ajusta a ninguno de los requisitos anteriores.

Sin embargo , aquí no hay ninguna restricción de programación que impida que lsse implique como una función integrada, que se ejecuta en el mismo proceso que el intérprete de bash. Las razones de diseño para que los comandos no se impliquen como elementos integrados de shell son:

  1. El shell debe estar separado del sistema de archivos; los comandos integrados no deben depender del funcionamiento correcto de ningún sistema de archivos o dispositivos periféricos
  2. Un comando que podría ser del tipo de sistema de archivos o del sistema operativo debería ser un ejecutable separado
  3. Un comando al que puede querer canalizar debe ser un proceso separado
  4. Un comando que desee ejecutar en segundo plano debe ser un ejecutable separado
  5. Un comando que tiene una gran cantidad de parámetros posibles se implementa mejor en un ejecutable separado
  6. Los comandos que deberían tener el mismo resultado, independientemente de qué tipo de shell (bash, csh, tsh, ...) los invoque, deben ser ejecutables independientes

En cuanto a la primera razón: desea que el caparazón sea lo más independiente y flexible posible. No desea que el shell se atasque en lsun montaje NFS que "no responde y sigue intentando".

En cuanto a la segunda razón: en muchos casos, es posible que desee utilizar un shell para un sistema que utiliza Busybox u otro sistema de archivos que tenga una lsimplementación diferente . O incluso use la misma fuente de shell en sistemas operativos que tienen lsimplementaciones diferentes .

En cuanto a la tercera razón: para expresiones como find . -type d | xargs ls -ladsería difícil o imposible implementarlas lsen el mismo proceso que el intérprete de shell.

En cuanto a la cuarta razón: algunos lscomandos pueden tardar mucho tiempo en completarse. Es posible que desee que el shell continúe haciendo otra cosa mientras tanto.


Nota: Vea esta publicación útil de Warren Young en respuesta a una pregunta similar.

Jonathan Ben-Avraham
fuente
Se perdió la facilidad de salida de tuberías si es un comando separado, y toda la programación que tomaría para canalizar una primitiva de shell en un ejecutable separado.
Bruce Ediger
@BruceEdiger: Qué placer recibir un comentario del estimado BE. ¡Gracias! Creo que la razón 3 cubre tu comentario, ¿no?
Jonathan Ben-Avraham
1
Estaba pensando más en la línea de cuán complicado sería el código fuente del shell si tuviera que manejar tuberías para procesos externos, y canalizar la salida de un comando interno como el hipotético lsen un proceso externo. Podría hacerse, pero sería complicado.
Bruce Ediger
1
Me temo que la mayoría, si no todos tus 5 puntos son discutibles. 1: ls es (con suerte) independiente de la implementación del sistema de archivos. Eso depende del kernel para proporcionar una interfaz coherente con la biblioteca y las aplicaciones estándar. 2: ls probablemente sea menos dependiente del sistema operativo que el shell. 3: los depósitos definitivamente permiten la construcción en tuberías. 4: los shells definitivamente permiten ejecutar builtins en segundo plano. 5: eso es bastante subjetivo.
jlliagre
1
@ JonathanBen-Avraham @BruceEdiger ¿Las cáscaras ya no manejan la caja de la tubería para las construcciones con subcapas? Por ejemplo, bashsalida alias | grep ls. entradacat /etc/passwd | while read a; do echo "$a"; done
Matt
2

lsNo requiere un proceso separado. Muy pocos comandos requieren un proceso separado: solo los que necesitan cambiar los privilegios.

Como regla general, los shells implementan comandos como incorporados solo cuando esos comandos deben implementarse como incorporados. Los comandos como alias, cd, exit, export, jobs, ... necesidad de leer o modificar algún estado interno de la cáscara, y por lo tanto no puede ser programas independientes. Los comandos que no tienen tales requisitos pueden ser comandos separados; De esta manera, se pueden llamar desde cualquier shell u otro programa.

Mirando la lista de incorporados en bash, solo los siguientes incorporados podrían implementarse como comandos separados. Para algunos de ellos, habría una ligera pérdida de funcionalidad.

  • command- pero perdería su utilidad en situaciones en las que es PATHposible que no se configure correctamente y el script se esté utilizando commandcomo parte de la configuración.
  • echo - Es una construcción para la eficiencia.
  • help - podría usar una base de datos separada, pero incrustar el texto de ayuda en el ejecutable del shell tiene la ventaja de hacer que el ejecutable del shell sea autónomo.
  • kill - Hay dos ventajas en tener un builtin incorporado: puede reconocer designaciones de trabajo además de las ID de proceso, y puede usarse incluso cuando no hay suficientes recursos para iniciar un proceso separado.
  • printf- por la misma razón que echo, y también para admitir la -vopción de poner la salida en una variable.
  • pwd - el incorporado ofrece la capacidad adicional de seguimiento lógico del directorio actual (dejando intactos los enlaces simbólicos en lugar de expandirlos).
  • test- Es una función integrada para la eficiencia (y bash también hace algo de magia con archivos llamados /dev/fd/…en algunos sistemas operativos).

Algunas conchas ofrecen un número significativo de incorporaciones adicionales. Hay faja , que es un shell diseñado para ser un binario independiente para reparaciones de emergencia (cuando algunos comandos externos pueden no ser utilizables). Tiene incorporado ls, llamado -ls, así como otras herramientas como -grepy -tar. Los componentes integrados de Sash tienen menos capacidades que los comandos completos. Zsh ofrece algunos componentes similares en su módulo zsh / files . No tiene ls, pero la expansión comodín ( echo *) y zstatpuede cumplir una función similar.

Gilles 'SO- deja de ser malvado'
fuente
2

Creo que algo que falta a la gente aquí es la complejidad de corte del lsprograma GNU en Linux. Comparando el tamaño del ejecutable de lslabash y dashconchas en mi sistema Debian, vemos que es bastante grande:

graeme@graeme:~$ ls -lh /bin/{ls,bash,dash}
-rwxr-xr-x 1 root root 953K Mar 30  2013 /bin/bash
-rwxr-xr-x 1 root root 115K Dec 25 20:25 /bin/dash
-rwxr-xr-x 1 root root 108K Jul 20 22:52 /bin/ls

Incluyendo un ls versión tan completa como la versión GNU bashaumentaría el tamaño del ejecutable en un 10%. ¡Es casi del mismo tamaño que la dashcarcasa completa !

La mayoría de los componentes integrados de shell se eligen porque se integran con el shell de una manera que los ejecutables externos no pueden (la pregunta señala cd , pero otro ejemplo es la versión bash de killintegrarse con el control de trabajo bash) o porque son comandos muy simples de implementar, dando una gran recompensa de velocidad vs tamaño ( truey falseson casi tan simples como se pone).

GNU lsha tenido un largo ciclo de desarrollo e implementa muchas opciones para personalizar qué / cómo se muestran los resultados. El uso de un ls incorporado por defecto perdería esta funcionalidad o aumentaría significativamente la complejidad y el tamaño del shell.

Graeme
fuente
1

cdestá integrado en el shell, lses un programa separado que verá en /bin/ls.

DopeGhoti
fuente
0

Esto hace lo que buscas:

printf "%s\n" *

También puede almacenar nombres de archivo en una matriz:

files=(`printf "%s\n" *`)  #items are separated by whitespace
echo ${#files[*]} files
for index in ${!a[*]}
do printf "%d: %s\n" $index ${a[$index]};
done

Pero no le importan los espacios en los nombres.
Esto pasa a variable y se preocupa por los espacios:

printf "%s\n" * | while read a; do echo $a; done
Costa
fuente