Solución:
Significa que los scripts de shell no se compilan, se interpretan: el shell interpreta los scripts de un comando a la vez y descubre cada vez cómo ejecutar cada comando. Eso tiene sentido para los scripts de shell, ya que de todos modos pasan la mayor parte del tiempo ejecutando otros programas.
Por otro lado, los programas en C generalmente se compilan: antes de que puedan ejecutarse, un compilador los convierte a código de máquina en su totalidad, de una vez por todas. Ha habido intérpretes de C en el pasado (como el intérprete de C de HiSoft en el Atari ST) pero eran muy inusuales. Hoy en día, los compiladores de C son muy rápidos; TCC es tan rápido que puede usarlo para crear “secuencias de comandos C”, con un #!/usr/bin/tcc -run
shebang, entonces tu pueden Cree programas en C que se ejecuten de la misma manera que los scripts de shell (desde la perspectiva de los usuarios).
Algunos lenguajes suelen tener tanto un intérprete como un compilador: BASIC es un ejemplo que me viene a la mente.
También puede encontrar los llamados compiladores de scripts de shell, pero los que he visto son solo envoltorios de confusión: todavía usan un shell para interpretar realmente el script. Como señala mtraceur, sin duda sería posible un compilador de scripts de shell adecuado, pero no muy interesante.
Otra forma de pensar en esto es considerar que la capacidad de interpretación de scripts de un shell es una extensión de su capacidad de manejo de la línea de comandos, lo que naturalmente conduce a un enfoque interpretado. C, por otro lado, fue diseñado para producir binarios independientes; esto conduce a un enfoque compilado. Los lenguajes que generalmente se compilan tienden a generar intérpretes también, o al menos analizadores de línea de comandos (conocidos como REPL, bucles de lectura-evaluación-impresión; un shell es en sí mismo un REPL).
Todo se reduce a la diferencia técnica entre cómo el programa que puede leer / escribir como un ser humano se convierte en las instrucciones de la máquina que entiende su computadora, y las diferentes ventajas y desventajas de cada método es la razón por la que algunos lenguajes están escritos para necesitar compiladores. , y algunos están escritos para ser interpretados.
Primero, la diferencia técnica
(Nota: estoy simplificando mucho aquí para abordar la pregunta. Para una comprensión más profunda, las notas técnicas al final de mi respuesta elaboran / refinan algunas de las simplificaciones aquí, y los comentarios sobre esta respuesta tienen algunas aclaraciones y discusiones útiles también ..)
Básicamente, existen dos categorías generales de lenguajes de programación:
- Otro programa (el “compilador”) lee su programa, determina los pasos que dice su código y luego escribe un nuevo programa en código de máquina (el “lenguaje” que su computadora entiende) que realiza esos pasos.
- Otro programa (el “intérprete”) lee su programa, determina qué pasos dice su código que debe hacer y luego hace esos pasos por sí mismo. No se crea ningún programa nuevo.
C está en la primera categoría (la C compilador traduce la C idioma en tu computadora codigo de maquina: el código de máquina se guarda en un archivo, y luego, cuando ejecuta ese código de máquina, hace lo que desea).
bash está en la segunda categoría (el bash Interprete lee la fiesta idioma y la fiesta Interprete hace lo que quiere: por lo que no hay un “módulo compilador” per se, el intérprete hace la interpretación y la ejecución, mientras que un compilador lee y traduce).
Es posible que ya hayas notado lo que esto significa:
Con C, haces el paso “interpretar” una vez, luego, siempre que necesite ejecutar el programa, simplemente dígale a su computadora que ejecute el código de la máquina; su computadora puede ejecutarlo directamente sin tener que “pensar” más.
Con bash, tienes que hacer el paso “interpretar” cada vez usted ejecuta el programa – su computadora está ejecutando el intérprete de bash, y el intérprete de bash hace un “pensamiento” adicional para averiguar lo que necesita hacer para cada comando, cada vez.
Por lo tanto, los programas en C requieren más CPU, memoria y tiempo para prepararse (el paso de compilación), pero menos tiempo y trabajo para ejecutarse. Los programas bash requieren menos CPU, memoria y tiempo para prepararse, pero más tiempo y trabajo para ejecutarse. Probablemente no note estas diferencias la mayor parte del tiempo porque las computadoras son muy rápidas hoy en día, pero sí marca la diferencia, y esa diferencia se suma cuando necesita ejecutar programas grandes o complicados, o muchos programas pequeños.
Además, debido a que los programas C se convierten en código de máquina (el “idioma nativo”) de la computadora, no puede tomar un programa y copiarlo en otra computadora con un código de máquina diferente (por ejemplo, Intel de 64 bits en Intel 32 -bit, o de Intel a ARM o MIPS o lo que sea). Tienes que dedicar tiempo a compilarlo para ese otro lenguaje de máquina de nuevo. Pero un programa bash se puede mover a otra computadora que tenga instalado el intérprete bash y funcionará bien.
Ahora el por qué parte de tu pregunta
Los creadores de C estaban escribiendo un sistema operativo y otros programas en hardware desde hace varias décadas, que estaba bastante limitado por los estándares modernos. Por varias razones, convertir los programas en el código de máquina de la computadora era la mejor manera de lograr ese objetivo en ese momento. Además, estaban haciendo el tipo de trabajo en el que era importante que el código que escribieran se ejecutara eficientemente.
Y los creadores del shell Bourne y bash querían lo contrario: querían escribir programas / comandos que pudieran ejecutarse de inmediato: en la línea de comandos, en una terminal, solo desea escribir una línea, un comando y tenerlo ejecutar. Y querían que los scripts que escribías funcionasen en cualquier lugar donde tuvieras instalado el programa / intérprete de shell.
Conclusión
Entonces, en resumen, no necesita un compilador para bash, pero necesita uno para C porque esos lenguajes se convierten en acciones de computadora reales de manera diferente, y esa forma diferente de hacerlo se eligió porque los lenguajes tenían objetivos diferentes.
Otros detalles / notas técnicos / avanzados
-
De hecho, podrías crear una C Interprete, o una fiesta compilador. No hay nada que impida que eso sea posible: es solo que esos lenguajes se crearon para diferentes propósitos. A menudo es más fácil simplemente reescribir el programa en otro lenguaje que escribir un buen intérprete o compilador para un lenguaje de programación complejo. Especialmente cuando esos idiomas tienen algo específico en lo que eran buenos y, en primer lugar, se diseñaron con una determinada forma de trabajar. C fue diseñado para ser compilado, por lo que le faltan muchas abreviaturas convenientes que desearía en un shell interactivo, pero es muy bueno para expresar una manipulación muy específica y de bajo nivel de datos / memoria e interactuar con el sistema operativo , que son tareas que a menudo se encuentra haciendo cuando desea escribir código compilado de manera eficiente. Mientras tanto, bash es muy bueno para ejecutar otros programas, redirigir archivos / descriptores de archivos y trabajar con cadenas de texto, y tiene una abreviatura conveniente para ellos porque son tareas que a menudo desea hacer en un shell interactivo.
-
Detalles más avanzados: en realidad, hay lenguajes de programación que son una mezcla de ambos tipos (traducen el código fuente “casi todo”, de modo que pueden hacer la mayor parte de la interpretación / “pensamiento” una vez, y solo un poco de la interpretación / “pensar” más adelante). Java, Python y muchos otros lenguajes modernos son en realidad mezclas de este tipo: intentan obtener algunos de los beneficios de portabilidad y / o desarrollo rápido de los lenguajes interpretados, y algo de la velocidad de los lenguajes compilados. Hay muchas formas posibles de combinar estos enfoques y los diferentes idiomas lo hacen de manera diferente. Si desea profundizar en este tema, puede leer sobre los lenguajes de programación que compilan en “bytecode” (que es como compilar en su propio “lenguaje de máquina” inventado que luego puede interpretar de manera rápida y eficiente), y “JIT “(Compilación Just-in-Time, en la que compila y tal vez incluso vuelve a compilar el programa a medida que lo interpreta o lo ejecuta).
-
Usted preguntó acerca del bit de ejecución: en realidad, el bit ejecutable solo está ahí para decirle al sistema operativo que ese archivo está permitido para ser ejecutado. Sospecho que la única razón por la que los scripts bash funcionan para usted sin el ejecutar El permiso es en realidad porque los está ejecutando desde dentro de un shell bash. Normalmente, el sistema operativo, cuando se le pide que ejecute un archivo sin el bit de ejecución establecido, solo devolverá un error. Pero algunos shells como bash verán ese error y se encargarán de ejecutar el archivo de todos modos, básicamente emulando los pasos que normalmente daría el sistema operativo (busque la línea “#!” Al comienzo del archivo e intente para ejecutar ese programa para interpretar el archivo, con un valor predeterminado de sí mismo o
/bin/sh
si no hay “#!” línea). -
A veces, un compilador ya está instalado en su sistema y, a veces, los IDE vienen con su propio compilador y / o ejecutan la compilación por usted. Esto puede hacer que un lenguaje compilado “se sienta” como un lenguaje no compilado para usar, pero la diferencia técnica sigue ahí.
-
Un lenguaje “compilado” no necesariamente se compila en código de máquina, y la compilación completa es un tema en sí mismo. Básicamente, el término se usa ampliamente: en realidad, puede referirse a algunas cosas. En un sentido específico, un “compilador” es simplemente un traductor de un idioma (generalmente un idioma de “nivel superior” más fácil de usar para los humanos) a otro idioma (generalmente un lenguaje de “nivel inferior” que es más fácil de usar para las computadoras) a veces, pero en realidad no muy a menudo, esto es código de máquina). Además, a veces, cuando la gente dice “compilador”, en realidad están hablando de varios programas que trabajan juntos (para un compilador C típico, en realidad son cuatro programas: el “preprocesador”, el compilador en sí, el “ensamblador” y el ” enlazador “).
Considere el siguiente programa:
2 Mars Bars
2 Milks
1 Bread
1 Corn Flakes
En el bash
De esta manera, deambulas por la tienda en busca de barras de Marte, finalmente las localizas, luego deambulas en busca de leche, etc. Esto funciona porque estás ejecutando un programa complejo llamado “Comprador experimentado” que puede reconocer un pan cuando ves uno y todos las otras complejidades de las compras. bash
es un programa bastante complejo.
Alternativamente, puede entregar su lista de compras a un compilador de compras. El compilador piensa por un momento y le da una nueva lista. Esta lista es LARGO, pero consta de instrucciones mucho más simples:
... lots of instructions on how to get to the store, get a shopping cart etc.
move west one aisle.
move north two sections.
move hand to shelf three.
grab object.
move hand to shopping cart.
release object.
... and so on and so forth.
Como puede ver, el compilador sabe exactamente dónde está todo en la tienda, por lo que no es necesaria toda la fase de “buscar cosas”.
Este es un programa por derecho propio y no necesita “Comprador experimentado” para ejecutarse. Todo lo que necesita es un humano con “Sistema operativo humano básico”.
Volviendo a los programas informáticos: bash
es un “comprador experimentado” y puede tomar un script y hacerlo sin compilar nada. El compilador de CA produce un programa independiente que ya no necesita ayuda para ejecutarse.
Tanto los intérpretes como los compiladores tienen sus ventajas y desventajas.