El propósito de esta pregunta es responder a una curiosidad, no resolver un problema informático en particular. La pregunta es: ¿por qué las utilidades obligatorias POSIX no suelen integrarse en las implementaciones de shell?
Por ejemplo, tengo un script que básicamente lee algunos archivos de texto pequeños y comprueba que estén formateados correctamente, pero tarda 27 segundos en ejecutarse en mi máquina, debido a una cantidad significativa de manipulación de cadenas. Esta manipulación de cadenas crea miles de nuevos procesos al llamar a varias utilidades, de ahí la lentitud. Estoy bastante seguro de que si algunos de los servicios públicos fueron construidos en, a saber grep
, sed
, cut
, tr
, y expr
, a continuación, la secuencia de comandos se ejecutaría en un segundo o menos (basado en mi experiencia en C).
Parece que habría muchas situaciones en las que construir estas utilidades marcaría la diferencia entre si una solución en el script de shell tiene un rendimiento aceptable.
Obviamente, hay una razón por la que se eligió no hacer estas utilidades integradas. Quizás tener una versión de una utilidad a nivel de sistema evita que varias shells utilicen varias versiones desiguales de esa utilidad. Realmente no puedo pensar en muchas otras razones para mantener la sobrecarga de crear tantos procesos nuevos, y POSIX define lo suficiente sobre las utilidades para que no parezca un gran problema tener diferentes implementaciones, siempre que sean POSIX obediente. Al menos no es un problema tan grande como la ineficiencia de tener tantos procesos.
printf
, etc.) se han incorporado a los shells cuando se consideraron lo suficientemente útiles.awk
es una utilidad obligatoria en POSIX, y especialmente adecuado (es decir, muy rápido) para implementar scripts que de otro modo podrían implementar usandosed
,cut
,tr
,grep
, yexpr
en un script de shell.Respuestas:
No se espera que los scripts de shell se ejecuten con ese tipo de velocidad. Si quieres mejorar la velocidad de tu script, pruébalo en perl. Si todavía es demasiado lento, tendrá que pasar a un lenguaje estáticamente escrito como java o c, o escribir un módulo C para perl que ejecute las partes que son demasiado lentas.
Shell es el primer nivel de creación de prototipos, si puede probar el concepto con shell, entonces pase a un mejor lenguaje de scripting que pueda verificar más límites, lo que requeriría acres de shell.
Se espera que un sistema operativo Unix incluya muchos programas pequeños que realizan tareas bien definidas que conforman una imagen más grande. Esto es bueno, ya que compartimenta programas más grandes. Eche un vistazo a qmail, por ejemplo, y compárelo con sendmail. qmail está hecho de muchos programas:
http://www.nrg4u.com/qmail/the-big-qmail-picture-103-p1.gif
Explotar el demonio de red no lo ayudaría a explotar el gestor de colas.
fuente
cd
opwd
.cd
está integrado , y en realidad tiene que serlo, porque cambiar el directorio de trabajo en un subproceso no afecta los procesos principales.Debido a que es compatible con POSIX, se requiere un sistema 1 para proporcionar la mayoría de las utilidades como comandos independientes.
Tenerlos incorporados implicaría que tienen que existir en dos lugares diferentes, dentro del caparazón y fuera de él. Por supuesto, sería posible implementar la versión externa mediante el uso de un contenedor de script de shell en el builtin incorporado, pero eso perjudicaría a las aplicaciones no shell que llaman a las utilidades.
Tenga en cuenta que BusyBox tomó el camino que sugirió al implementar muchos comandos internamente y proporcionar la variante independiente mediante enlaces a sí mismo. Un problema es que si bien el conjunto de comandos puede ser bastante grande, las implementaciones a menudo son un subconjunto del estándar, por lo que no son compatibles.
Tenga en cuenta también que, al menos
ksh93
,bash
yzsh
vaya más allá al proporcionar métodos personalizados para que el shell en ejecución cargue dinámicamente los builtins desde bibliotecas compartidas. Técnicamente, nada impide que todas las utilidades POSIX se implementen y estén disponibles como incorporadas.Finalmente, generar nuevos procesos se ha convertido en una operación bastante rápida con sistemas operativos modernos. Si realmente se ve afectado por un problema de rendimiento, puede haber algunas mejoras para que sus scripts se ejecuten más rápido.
1 POSIX.1-2008
fuente
fork
no seguido porexec
;fork
Hoy en día es una operación muy ligera en comparación conexec
.nofork
órdenes internas que tienen del orden de 10 veces menos sobrecarga quenoexec
builtins, que a su vez tenía ~ 5x menos sobrecarga que tenedor + exec de un binario independiente. Definiciones según unix.stackexchange.com/a/274322/29483 Es interesante que busybox no lo seanofork
todo, aunque sé que algunos códigos de busybox se acortan al no limpiar la memoria, y solo se basan en un proceso de corta duración.Del manual de referencia de BASH ,
Como estoy seguro de que has escuchado, la filosofía de UNIX se basa en gran medida en múltiples aplicaciones que tienen una funcionalidad limitada. Cada incorporado tiene una muy buena razón por la que está incorporado. Todo lo demás no lo está. Creo que una clase de preguntas más interesante es, "¿por qué exactamente está
pwd
incorporado?"fuente
cd
sería un mejor ejemplo aquí de algo que es imposible de implementar como una herramienta separada.cd
tiene que ser incorporado,pwd
no. Entonces, ¿por qué losbash
implementadores decidieron incluirlo?/bin/bash
existe, pero sigue siendo una construcción. Vea la lista de incorporados en gnu.org/software/bash/manual/html_node/…Los muchachos de AT&T se preguntaron lo mismo
Si nos fijamos en la historia del AT&T Software Toolkit (actualmente latente en Github desde que el equipo central se fue), esto es exactamente lo que hicieron con el shell AT&T Korn, también conocido como ksh93.
El rendimiento siempre fue parte de la motivación para los mantenedores de ksh93, y al compilar ksh puede elegir construir muchas utilidades POSIX comunes como bibliotecas cargadas dinámicamente. Al vincular estos comandos a un nombre de directorio como
/opt/ast/bin
, puede controlar qué versión del comando se usará, en función de la posición de ese nombre de directorio$PATH
.Ejemplos:
La lista completa se puede encontrar en el repositorio github ast .
Tenga en cuenta que la mayoría de las herramientas de AST tienen su propia procedencia y diferirían fuertemente de las implementaciones de GNU más comunes. El equipo de investigación de AT&T cumplió con los estándares oficiales, que era la forma de lograr la interoperabilidad cuando no se podía compartir el código.
fuente
Por lo tanto, no reunimos recursos para optimizar la herramienta original, para satisfacer cada deseo específico. Creo que lo que necesitamos explicar es cuánto habría costado implementar este deseo específico.
Esta es una mala suposición :-P.
Los sistemas post-POSIX continúan siendo más potentes y convenientes por buenas razones; como estándar después de los hechos, nunca se pone al día.
Ubuntu comenzó un esfuerzo para cambiar a un shell POSIX simplificado para secuencias de comandos, para optimizar el antiguo proceso de inicio de System V init. No digo que haya fallado, pero desencadenó muchos errores que tuvieron que limpiarse: "bashisms", scripts que se ejecutaron
/bin/sh
mientras se suponía que lasbash
funciones estaban disponibles.POSIX sh no es un buen lenguaje de programación de propósito general. Su propósito principal es funcionar bien como un shell interactivo. Tan pronto como comience a guardar sus comandos en un script, tenga en cuenta que se acerca a una tarpit de Turing . Por ejemplo, no es posible detectar fallas en medio de una tubería normal .
bash
agregadoset -o pipefail
para esto, pero esto no está en POSIX.Casi todas las utilidades más complejas que proporcionan funciones útiles pero no estandarizadas similares
true
.Para la clase de tarea que delinees, puedes dibujar una línea aproximada para Awk, Perl y hoy en día Python. Se crearon diferentes herramientas y evolucionaron de forma independiente. ¿Esperaría, por ejemplo, que GNU Awk se incluyera en un libutilposixextended?
No estoy diciendo que ahora tengamos un enfoque universalmente mejor al que pueda señalarle. Tengo una debilidad por Python. Awk es sorprendentemente poderoso, aunque algunas características de GNU Awk me han frustrado. Pero el punto es que procesar grandes cantidades de cadenas individualmente (presumiblemente de las líneas de los archivos) no era un objetivo de diseño del shell POSIX.
fuente
cat -@fnord foo
el shell, debería decidir eso, ya que no sabe qué-@
significa que necesitaría invocar el comando real, pero dado quecat <foo >bar
el shell no debería generar otro proceso.También está la cuestión de: ¿En qué shell lo construirías?
La mayoría de los sistemas Unix / Linux tienen múltiples shells diferentes que se desarrollan de forma independiente (sh / bash / korn / ???). Si construye las herramientas en el shell, terminaría con una implementación diferente de estas herramientas para cada shell. Esto provocaría una sobrecarga, y podría terminar con diferentes características / errores en, por ejemplo, grep, dependiendo de qué shell utilizó para invocarlo.
fuente
Muchos han respondido bien. Solo pretendo complementar esas respuestas. Creo que la filosofía de UNIX es que una herramienta debe hacer una cosa y hacerlo bien. Si uno trata de hacer una herramienta que lo abarque todo, hay muchos más lugares para el fracaso. Limitar la funcionalidad de esta manera hace que un conjunto de herramientas sea confiable.
Además, tenga en cuenta que si se integraran funciones como sed o grep en el shell, ¿sería tan fácil invocar desde la línea de comandos cuando lo desee?
Para terminar, considere que algunas de las funcionalidades que desea tener en BASH están en BASH . Por ejemplo, la capacidad para la coincidencia de RE en BASH se implementa utilizando el operador binario = ~ (consulte Gramática de Shell en la página del manual para obtener más información específica sobre la discusión de la construcción [[]] para if ). Como un ejemplo muy rápido, digamos que estoy buscando un archivo de 2 dígitos hexadecimales:
En cuanto a la funcionalidad de tipo sed , busque en Expansión de parámetros en el encabezado Expansión de la misma página de manual. Verás una gran cantidad de cosas que puedes hacer que recuerdan a sed. La mayoría de las veces uso sed para hacer algún cambio de tipo de sustitución en el texto. A partir de lo anterior:
Al final, ¿es lo anterior "mejor" que?
fuente
Esto es, supongo, un accidente histórico.
Cuando se creó UNIX a fines de los años sesenta y principios de los setenta, las computadoras no tenían casi tanta memoria como hoy en día. Hubiera sido posible, en ese momento, implementar toda esta funcionalidad como componentes integrados de shell, pero debido a las limitaciones de memoria, habrían tenido que limitar la cantidad de funcionalidad que podrían implementar, o arriesgarse de memoria y / o intercambiar basura problemas.
Por otro lado, al implementar la funcionalidad dada como programas separados, y al hacer las dos llamadas al sistema requeridas para comenzar un nuevo proceso lo más ligero posible, podrían crear un entorno de secuencias de comandos que no tenga esos problemas y que todavía se ejecute a un nivel razonable velocidad.
Por supuesto, una vez que esas cosas se implementen como procesos separados, las personas los iniciarán desde programas que no son shells, y luego tendrán que permanecer así, o de repente todo este software comenzará a romperse.
Sin embargo, eso no quiere decir que no pueda implementar alguna funcionalidad dos veces, y de hecho algunos shells implementan alguna funcionalidad que se supone que es un programa externo como un shell incorporado; por ejemplo, bash implementa el
echo
comando como incorporado, pero también hay un/usr/bin/echo
fuente