J'ai écrit un script bash et je l'ai exécuté sans le compiler au préalable. Cela a parfaitement fonctionné. Il peut fonctionner avec ou sans autorisations, mais en ce qui concerne les programmes C, nous devons compiler le code source. Pourquoi?
J'ai écrit un script bash et je l'ai exécuté sans le compiler au préalable. Cela a parfaitement fonctionné. Il peut fonctionner avec ou sans autorisations, mais en ce qui concerne les programmes C, nous devons compiler le code source. Pourquoi?
Réponses:
Cela signifie que les scripts shell ne sont pas compilés, ils sont interprétés: le shell interprète les scripts une commande à la fois et explique à chaque fois comment exécuter chaque commande. Cela a du sens pour les scripts shell, car ils passent de toute façon la plupart de leur temps à exécuter d'autres programmes.
Les programmes C, d'autre part, sont généralement compilés: avant de pouvoir être exécutés, un compilateur les convertit en code machine dans leur intégralité, une fois pour toutes. Il y avait des interprètes C dans le passé (comme l' interprète C de HiSoft sur la Atari ST) mais ils étaient très inhabituels. De nos jours, les compilateurs C sont très rapides; TCC est si rapide que vous pouvez l'utiliser pour créer des "scripts C", avec un #!/usr/bin/tcc -run
shebang, vous pouvez donc créer des programmes C qui s'exécutent de la même manière que les scripts shell (du point de vue des utilisateurs).
Certaines langues ont généralement à la fois un interprète et un compilateur: BASIC est un exemple qui me vient à l'esprit.
Vous pouvez également trouver des soi-disant compilateurs de script shell, mais ceux que j'ai vus ne sont que des wrappers obscurcissants: ils utilisent toujours un shell pour interpréter réellement le script. Comme le souligne mtraceur , un compilateur de scripts shell approprié serait certainement possible, mais pas très intéressant.
Une autre façon de penser à ce sujet est de considérer que la capacité d'interprétation de script d'un shell est une extension de sa capacité de gestion en ligne de commande, ce qui conduit naturellement à une approche interprétée. C d'autre part a été conçu pour produire des binaires autonomes; cela conduit à une approche compilée. Les langues qui sont généralement compilées ont également tendance à faire germer des interprètes, ou au moins des analyseurs de ligne de commande (appelés REPL, boucles de lecture-évaluation-impression ; un shell est lui-même un REPL).
execve
, open
, close
, read
, write
, et pipe
syscalls, entrecoupées de quelques - uns getenv
, setenv
et les opérations hashmap / tableau interne (pour les variables non exportées ), etc. Le shell Bourne et ses dérivés ne sont pas non plus des langages de programmation qui bénéficient autant de modifications de compilateur de bas niveau comme le reclassement de code, etc.
Considérez le programme suivant:
2 Mars Bars
2 Milks
1 Bread
1 Corn Flakes
En bash
chemin, vous vous promenez dans le magasin à la recherche de barres de mars, enfin les localisez, puis vous vous promenez à la recherche de lait, etc. et toutes les autres complexités du shopping. bash
est un programme assez complexe.
Alternativement, vous pouvez remettre votre liste de courses à un compilateur de courses. Le compilateur réfléchit un moment et vous propose une nouvelle liste. Cette liste est longue , mais se compose d'instructions beaucoup plus 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.
Comme vous pouvez le voir, le compilateur sait exactement où tout se trouve dans la boutique, donc toute la phase de "recherche de choses" n'est pas nécessaire.
Il s'agit d'un programme à part entière et n'a pas besoin de "Shopper expérimenté" pour s'exécuter. Tout ce dont il a besoin, c'est d'un humain doté du «système d'exploitation humain de base».
Revenir aux programmes informatiques: bash
est "Shopper expérimenté" et peut prendre un script et le faire sans rien compiler. Le compilateur AC produit un programme autonome qui n'a plus besoin d'aide pour s'exécuter.
Les interprètes et les compilateurs ont leurs avantages et leurs inconvénients.
Tout se résume à la différence technique entre la façon dont le programme que vous pouvez lire / écrire en tant qu'être humain est converti en instructions machine que votre ordinateur comprend - et les différents avantages et inconvénients de chaque méthode sont la raison pour laquelle certaines langues sont écrites pour avoir besoin de compilateurs et certains sont écrits pour être interprétés.
(Remarque: je simplifie beaucoup ici pour répondre à la question. Pour une compréhension plus approfondie, les notes techniques au bas de ma réponse élaborent / affinent certaines des simplifications ici, et les commentaires sur cette réponse ont quelques clarifications et discussions utiles ..)
Il existe essentiellement deux catégories générales de langages de programmation:
C est dans la première catégorie (le compilateur C traduit le langage C en code machine de votre ordinateur : le code machine est enregistré dans un fichier, puis lorsque vous exécutez ce code machine, il fait ce que vous voulez).
bash est dans la deuxième catégorie (l' interpréteur bash lit le langage bash et l' interpréteur bash fait ce que vous voulez: il n'y a donc pas de "module de compilation" en soi, l'interpréteur fait l'interprétation et l'exécution, tandis qu'un compilateur fait la lecture et la traduction) .
Vous avez peut-être déjà remarqué ce que cela signifie:
Avec C, vous effectuez l'étape "interpréter" une fois , puis chaque fois que vous devez exécuter le programme, vous dites simplement à votre ordinateur d'exécuter le code machine - votre ordinateur peut simplement l'exécuter directement sans avoir à faire de "réflexion" supplémentaire.
Avec bash, vous devez effectuer l'étape "interpréter" chaque fois que vous exécutez le programme - votre ordinateur exécute l'interpréteur bash, et l'interpréteur bash réfléchit davantage pour comprendre ce qu'il doit faire pour chaque commande, à chaque fois .
Les programmes C prennent donc plus de CPU, de mémoire et de temps à préparer (l'étape de compilation) mais moins de temps et de travail à exécuter. Les programmes bash prennent moins de CPU, de mémoire et de temps à préparer, mais plus de temps et de travail à exécuter. Vous ne remarquez probablement pas ces différences la plupart du temps parce que les ordinateurs sont très rapides de nos jours, mais cela fait une différence, et cette différence s'ajoute lorsque vous devez exécuter des programmes gros ou compliqués, ou beaucoup de petits programmes.
De plus, comme les programmes C sont convertis en code machine (la "langue maternelle") de l'ordinateur, vous ne pouvez pas prendre un programme et le copier sur un autre ordinateur avec un code machine différent (par exemple, Intel 64 bits sur Intel 32 -bit, ou d'Intel à ARM ou MIPS ou autre). Vous devez passer le temps de le compiler pour cette autre langage machine à nouveau . Mais un programme bash peut simplement être déplacé vers un autre ordinateur sur lequel l'interpréteur bash est installé, et il fonctionnera très bien.
Les fabricants de C écrivaient un système d'exploitation et d'autres programmes sur du matériel d'il y a plusieurs décennies, qui était plutôt limité par les normes modernes. Pour diverses raisons, la conversion des programmes en code machine de l'ordinateur était pour eux le meilleur moyen d'atteindre cet objectif à l'époque. De plus, ils faisaient le genre de travail où il était important que le code qu'ils écrivaient fonctionne efficacement .
Et les créateurs du shell Bourne et de bash voulaient le contraire: ils voulaient écrire des programmes / commandes qui pourraient être exécutés immédiatement - sur la ligne de commande, dans un terminal, vous voulez juste écrire une ligne, une commande et l'avoir exécuter. Et ils voulaient que les scripts que vous écriviez fonctionnent partout où vous avez installé l'interpréteur / programme shell.
Donc, en bref, vous n'avez pas besoin d'un compilateur pour bash mais vous en avez besoin d'un pour C car ces langages sont convertis en actions informatiques réelles différemment, et ces différentes façons de faire qui ont été choisies parce que les langages avaient des objectifs différents.
Vous pourriez en fait créer un interpréteur C ou un compilateur bash. Rien ne l'empêche d'être possible: ce sont juste ces langues qui ont été faites à des fins différentes. Il est souvent plus facile de simplement réécrire le programme dans un autre langage que d'écrire un bon interprète ou compilateur pour un langage de programmation complexe. Surtout quand ces langues ont une chose spécifique, elles étaient douées et ont été conçues avec une certaine façon de travailler en premier lieu. C a été conçu pour être compilé, il manque donc beaucoup de raccourcis pratiques que vous souhaiteriez dans un shell interactif, mais il est très bon pour exprimer une manipulation très spécifique et de bas niveau des données / mémoire et interagir avec le système d'exploitation , tâches que vous vous trouvez souvent à effectuer lorsque vous souhaitez écrire du code compilé efficacement. Pendant ce temps, bash est très bon pour exécuter d'autres programmes,
Détail plus avancé: il existe en fait des langages de programmation qui sont un mélange des deux types (ils traduisent le code source "la plupart du temps", de sorte qu'ils peuvent faire la plupart de l'interprétation / "penser" une fois, et ne le font que peu de l'interprétation / "pensée" plus loin). Java, Python et de nombreux autres langages modernes sont en fait de tels mélanges: ils essaient de vous offrir certains des avantages de portabilité et / ou de développement rapide des langages interprétés, et une partie de la vitesse des langages compilés. Il existe de nombreuses façons de combiner de telles approches, et différentes langues le font différemment. Si vous voulez approfondir ce sujet, vous pouvez lire sur les langages de programmation qui se compilent en "bytecode" (ce qui est un peu comme la compilation dans votre propre "langage machine"
Vous avez demandé le bit d' exécution: En fait, le bit exécutable est seulement là pour dire le système d'exploitation que ce fichier est autorisé à exécuter. Je soupçonne que la seule raison pour laquelle les scripts bash fonctionnent pour vous sans l' autorisation d' exécution est en fait parce que vous les exécutez depuis l'intérieur d'un shell bash. Normalement, le système d'exploitation, lorsqu'on lui demande d'exécuter un fichier sans le jeu de bits d'exécution, renvoie simplement une erreur. Mais certains shells comme bash verront cette erreur et prendront la décision d'exécuter le fichier de toute façon, en émulant essentiellement les étapes que le système d'exploitation devrait normalement suivre (recherchez la ligne "#!" Au début du fichier et essayez pour exécuter ce programme pour interpréter le fichier, avec une valeur par défaut de lui-même ou /bin/sh
s'il n'y a pas de ligne "#!").
Parfois, un compilateur est déjà installé sur votre système, et parfois les IDE sont livrés avec leur propre compilateur et / ou exécutent la compilation pour vous. Cela pourrait faire en sorte qu'un langage compilé "ressemble" à un langage non compilé à utiliser, mais la différence technique est toujours là.
Un langage "compilé" n'est pas nécessairement compilé en code machine, et l'ensemble de la compilation est un sujet en soi. Fondamentalement, le terme est utilisé largement: il peut en fait se référer à quelques éléments. Dans un sens spécifique, un "compilateur" est juste un traducteur d'une langue (généralement une langue "de niveau supérieur" plus facile à utiliser pour les humains) dans une autre langue (généralement une langue "de niveau inférieur" qui est plus facile à utiliser pour les ordinateurs - parfois, mais en fait pas très souvent, c'est du code machine). De plus, parfois, quand les gens disent "compilateur", ils parlent vraiment de plusieurs programmes travaillant ensemble (pour un compilateur C typique, il s'agit en fait de quatre programmes: le "pré-processeur", le compilateur lui-même, l '"assembleur" et le " éditeur de liens ").
Les langages de programmation / scripting peuvent être compilés ou interprétés.
Les exécutables compilés sont toujours plus rapides et de nombreuses erreurs peuvent être détectées avant l'exécution.
Les langages interprétés sont généralement plus simples à écrire et à adapter étant moins stricts que les langages compilés, et ne nécessitent pas de compilation, ce qui les rend plus faciles à distribuer.
Imaginez que l'anglais n'est pas votre langue maternelle (cela pourrait être assez facile pour vous si l'anglais n'est pas votre langue maternelle).
Il y a 3 façons de lire ceci:
Les ordinateurs ont une sorte de «langue maternelle» - une combinaison d'instructions que le processeur comprend et d'instructions que le système d'exploitation (par exemple Windows, Linux, OSX, etc.) comprend. Cette langue n'est pas lisible par l'homme.
Les langages de script, tels que Bash, entrent généralement dans les catégories 1 et 2. Ils prennent une ligne à la fois, traduisent cette ligne et l'exécutent, puis passent à la ligne suivante. Sur Mac et Linux, plusieurs interprètes différents sont installés par défaut pour différentes langues, comme Bash, Python et Perl. Sous Windows, vous devez les installer vous-même.
De nombreux langages de script font un peu de prétraitement - essayez d'accélérer l'exécution en compilant des morceaux de code qui seront exécutés souvent ou qui autrement ralentiraient l'application. Certains termes dont vous pourriez entendre parler incluent la compilation Ahead-of-time (AOT) ou Just-in-time (JIT).
Enfin, les langages compilés - comme C - traduisent l'ensemble du programme avant de pouvoir les exécuter. Cela a l'avantage que la traduction peut être effectuée sur une machine différente de l'exécution, donc lorsque vous donnez le programme à l'utilisateur, alors qu'il peut encore y avoir des bogues, plusieurs types d'erreurs peuvent déjà être nettoyés. Tout comme si vous aviez donné cela à votre traducteur, et je mentionne à quoi garboola mizene resplunks
cela pourrait ressembler à un anglais valide pour vous, mais le traducteur peut vous dire que je dis des bêtises. Lorsque vous exécutez un programme compilé, il n'a pas besoin d'interprète - il est déjà dans la langue maternelle de l'ordinateur
Cependant, il y a un inconvénient aux langues compilées: j'ai mentionné que les ordinateurs ont une langue native, composée de fonctionnalités du matériel et du système d'exploitation - eh bien, si vous compilez votre programme sous Windows, vous ne vous attendez pas à ce que le programme compilé s'exécute sur un Mac. Certaines langues contournent cela en compilant une sorte de langue à mi-chemin - un peu comme l'anglais Pidgin - de cette façon, vous obtenez les avantages d'une langue compilée, ainsi qu'une petite augmentation de vitesse, mais cela signifie que vous devez regrouper un interprète avec votre code (ou utilisez celui qui est déjà installé).
Enfin, votre IDE compilait probablement vos fichiers pour vous et pourrait vous informer des erreurs avant d'exécuter le code. Parfois, cette vérification d'erreur peut être plus approfondie que ne le fera le compilateur. Un compilateur ne vérifie souvent que ce dont il a besoin pour produire un code natif sensible. Un IDE exécutera souvent quelques vérifications supplémentaires et peut vous dire, par exemple, si vous avez défini une variable deux fois, ou si vous avez importé quelque chose que vous n'avez pas utilisé.
Beaucoup de gens parlent d'interprétation et de compilation, mais je pense que cela peut être un peu trompeur si vous y regardez de près car certains langages interprétés sont en fait compilés dans un bytecode intermédiaire avant l'exécution.
En fin de compte, la vraie raison pour laquelle les programmes C doivent être compilés au format exécutable est que l'ordinateur doit faire beaucoup de travail pour transformer le code dans un fichier source C en quelque chose qu'il peut exécuter, il est donc logique d'enregistrer le produit de tout cela fonctionne dans un fichier exécutable, vous n'avez donc pas besoin de le faire à chaque fois que vous souhaitez exécuter votre programme.
D'un autre côté, l'interpréteur Shell doit faire très peu de travail pour convertir un script shell en "opérations machine". Fondamentalement, il suffit de lire le script ligne par ligne, de le diviser en espaces blancs, de configurer des redirections de fichiers et des pipelines, puis de faire un fork + un exécutable. Étant donné que la surcharge d'analyse et de traitement de l'entrée textuelle d'un script shell est très faible par rapport au temps qu'il faut pour lancer les processus dans le script shell, il serait exagéré de compiler les scripts shell dans un format de machine intermédiaire au lieu de simplement interpréter directement le code source.