345 votes

Pourquoi les langages de script (par exemple Perl, Python, Ruby) ne conviennent-ils pas comme langages shell ?

Quelles sont les différences entre les langages shell comme bash , zsh , poisson et les langages de script ci-dessus qui les rendent plus adaptés à l'interpréteur de commandes ?

Lorsqu'on utilise la ligne de commande, les langages shell semblent beaucoup plus faciles. Il me semble beaucoup plus facile d'utiliser bash par exemple que d'utiliser le profil shell dans ipython, malgré les rapports qui disent le contraire . Je pense que la plupart des gens seront d'accord avec moi pour dire qu'une grande partie de la programmation à moyenne et grande échelle est plus facile en Python qu'en bash. J'utilise Python comme le langage avec lequel je suis le plus familier, il en va de même pour Perl et Ruby.

J'ai essayé d'en expliquer la raison, mais je n'y suis pas parvenu, si ce n'est en supposant que le traitement différent des cordes dans les deux cas y est pour quelque chose.

La raison de cette question est que j'espère développer un langage utilisable dans les deux. Si vous connaissez un tel langage, merci de le poster également.

Comme l'explique S.Lott, la question doit être clarifiée. Je m'interroge sur les caractéristiques de l'obus langue par rapport à celle des langages de script. La comparaison ne porte donc pas sur les caractéristiques des différents langages interactifs ( REPL ) tels que l'historique et la substitution de ligne de commande. Une expression alternative pour la question serait :

Un langage de programmation qui convient à la conception de systèmes complexes peut-il en même temps être capable d'exprimer des lignes uniques utiles qui peuvent accéder au système de fichiers ou contrôler des travaux ? Un langage de programmation peut-il utilement évoluer vers le haut comme vers le bas ?

471voto

Jörg W Mittag Points 153275

Il y a quelques différences qui me viennent à l'esprit ; je ne fais que réfléchir, sans ordre particulier :

  1. Python & Co. sont conçus pour être bons en scripting. Bash & Co. sont conçus pour être seulement bon en script, sans aucun compromis. Autrement dit, Python est conçu pour être bon à la fois pour les scripts et pour les autres applications, alors que Bash ne s'intéresse qu'aux scripts.

  2. Bash & Co. sont non typés, Python & Co. sont fortement typés, ce qui signifie que le nombre 123 la chaîne 123 et le fichier 123 sont très différentes. Ils ne sont cependant pas statiquement typés, ce qui signifie qu'ils doivent avoir des littéraux différents pour ceux-ci, afin de les séparer.
    Exemple :

                    | Ruby             | Bash    
    -----------------------------------------
    number          | 123              | 123
    string          | '123'            | 123
    regexp          | /123/            | 123
    file            | File.open('123') | 123
    file descriptor | IO.open('123')   | 123
    URI             | URI.parse('123') | 123
    command         | `123`            | 123
  3. Python & Co. sont conçus pour être évolutifs en haut à des programmes de 10000, 100000, peut-être même 1000000 lignes, Bash & Co. sont conçus pour évoluer en bas à 10 caractère programmes.

  4. En Bash & Co, les fichiers, les répertoires, les descripteurs de fichiers, les processus sont tous des objets de première classe, en Python, seuls les objets Python sont de première classe, si vous voulez manipuler des fichiers, des répertoires etc , vous devez d'abord les envelopper dans un objet Python.

  5. La programmation Shell est fondamentalement une programmation par flux de données. Personne ne s'en rend compte, pas même les personnes qui écrivent les shells, mais il s'avère que les shells sont assez bons pour cela, et les langages à usage général pas tellement. Dans le monde de la programmation à usage général, le flux de données semble être considéré comme un modèle de concurrence et non comme un paradigme de programmation.

J'ai le sentiment que tenter de résoudre ces problèmes en ajoutant des fonctionnalités ou des DSL à un langage de programmation polyvalent ne fonctionne pas. Du moins, je n'ai pas encore vu d'implémentation convaincante de cette méthode. Il existe RuSH (Ruby shell), qui tente d'implémenter un shell en Ruby, il y a aussi ruée vers qui est un DSL interne pour la programmation du shell en Ruby. Hotwire qui est un shell Python, mais aucun d'entre eux ne peut rivaliser avec Bash, Zsh, fish et leurs amis.

En fait, IMHO, la meilleure coquille actuelle est Microsoft PowerShell ce qui est très surprenant étant donné que pour plusieurs décennies Aujourd'hui, Microsoft a toujours eu le pire coquilles evar . Je veux dire, COMMAND.COM ? Vraiment ? (Malheureusement, ils ont toujours un terminal merdique. C'est toujours l'"invite de commande" qui existe depuis, quoi ? Windows 3.0 ?)

PowerShell a été créé en ignorant tout ce que Microsoft a fait jusqu'à présent ( COMMAND.COM , CMD.EXE VBScript, JScript) et de partir de l'interpréteur de commandes Unix, puis de supprimer tous les éléments de rétrocompatibilité (comme les backticks pour la substitution des commandes) et de les modifier un peu pour les rendre plus adaptés à Windows (comme l'utilisation du backtick, désormais inutilisé, comme caractère d'échappement au lieu de la barre oblique inversée qui est le caractère de séparation des composants du chemin dans Windows). C'est ensuite que la magie opère.

Ils abordent problèmes 1 et 3 d'en haut, en faisant essentiellement le choix inverse par rapport à Python. Python s'intéresse d'abord aux grands programmes, puis aux scripts. Bash ne s'intéresse qu'aux scripts. PowerShell s'intéresse d'abord aux scripts, puis aux grands programmes. Un moment décisif pour moi a été de regarder la vidéo d'une interview de Jeffrey Snover (le concepteur principal de PowerShell). L'intervieweur lui a demandé quelle taille de programme on pouvait écrire avec PowerShell et Snover a répondu sans hésiter : "80 caractères". À ce moment-là, j'ai réalisé que c'est enfin un gars chez Microsoft qui "comprend" la programmation shell (probablement en rapport avec le fait que PowerShell était ni développé par le groupe chargé des langages de programmation de Microsoft (c'est-à-dire les nerds des mathématiques du lambda-calcul) ni par le groupe chargé des systèmes d'exploitation (les nerds du noyau), mais plutôt par le groupe chargé des serveurs (c'est-à-dire les administrateurs système qui, en fait utiliser shells)), et que je devrais probablement me pencher sérieusement sur PowerShell.

Numéro 2 est résolu en faisant en sorte que les arguments soient typés statiquement. Ainsi, vous pouvez écrire simplement 123 et PowerShell sait s'il s'agit d'une chaîne de caractères, d'un nombre ou d'un fichier, car la cmdlet (c'est ainsi que l'on appelle les commandes shell dans PowerShell) déclare les types de ses arguments au shell. Cela a des ramifications assez profondes : contrairement à Unix, où chaque commande est responsable de l'analyse de ses propres arguments (l'interpréteur de commandes transmet essentiellement les arguments sous la forme d'un tableau de chaînes), l'analyse des arguments dans PowerShell est effectuée par la commande coquille . Les cmdlets spécifient toutes leurs options, tous leurs drapeaux et tous leurs arguments, ainsi que leurs types, leurs noms et leur documentation ( !) à l'interpréteur de commandes, qui peut alors effectuer l'analyse des arguments, la complétion de tabulation, l'IntelliSense, les popups de documentation en ligne, etc. en un seul endroit centralisé. (Ceci n'est pas révolutionnaire, et les concepteurs de PowerShell reconnaissent les shells tels que le DIGITAL Command Language (DCL) et le IBM OS/400 Command Language (CL) comme de l'art antérieur. Pour quiconque a déjà utilisé un AS/400, cela devrait vous sembler familier. Dans l'OS/400, vous pouvez écrire une commande shell et si vous ne connaissez pas la syntaxe de certains arguments, vous pouvez simplement les laisser de côté et appuyer sur la touche F4 qui fera apparaître un menu (similaire à un formulaire HTML) avec des champs étiquetés, une liste déroulante, des textes d'aide, etc. Ceci n'est possible que parce que le système d'exploitation connaît tous les arguments possibles et leurs types). Dans l'interpréteur de commandes Unix, ces informations sont souvent dupliquées trois fois : dans le code d'analyse des arguments de la commande elle-même, dans la section bash-completion script pour la complétion des tabulations et dans la page de manuel.

Numéro 4 est résolu par le fait que PowerShell opère sur des objets fortement typés, ce qui inclut des choses comme les fichiers, les processus, les dossiers, etc.

Numéro 5 est particulièrement intéressant, parce que PowerShell est le seul shell que je connaisse, où les personnes qui l'ont écrit étaient en fait conscient du fait que les shells sont essentiellement des moteurs de flux de données et l'a délibérément implémenté comme un moteur de flux de données.

Une autre caractéristique intéressante de PowerShell est la convention de dénomination : toutes les cmdlets sont nommées Action-Object et de plus, il existe également des noms normalisés pour des actions et des objets spécifiques. (Encore une fois, cela devrait être familier aux utilisateurs de l'OS/400.) Par exemple, tout ce qui est lié à la réception d'une information est appelé Get-Foo . Et tout ce qui opère sur des (sous-)objets est appelé Bar-ChildItem . Donc, l'équivalent de ls es Get-ChildItem (bien que PowerShell fournisse également des alias intégrés). ls y dir  - en fait, chaque fois que cela a un sens, ils fournissent à la fois Unix et CMD.EXE les alias ainsi que les abréviations ( gci dans ce cas)).

Mais le caractéristique dominante IMO est le pipeline d'objets fortement typés. Bien que PowerShell soit dérivé de l'interpréteur de commandes Unix, il existe une distinction très importante : dans Unix, toutes les communications (à la fois via les pipes et les redirections ainsi que via les arguments de commande) se font avec des chaînes de caractères non typées et non structurées. Dans PowerShell, il s'agit d'objets structurés et fortement typés. C'est tellement puissant que je me demande sérieusement pourquoi personne d'autre n'y a pensé. (Dans mon shell scripts, j'estime que jusqu'à un tiers des commandes ne sont là que pour servir d'adaptateur entre deux autres commandes qui ne sont pas d'accord sur un format textuel commun. Beaucoup de ces adaptateurs disparaissent dans PowerShell, car les cmdlets échangent des objets structurés plutôt que du texte non structuré. Et si vous regardez à l'intérieur de les commandes, alors elles se composent essentiellement de trois étapes : analyser l'entrée textuelle en une représentation d'objet interne, manipuler les objets, les reconvertir en texte. Encore une fois, les première et troisième étapes disparaissent, car les données arrivent déjà sous forme d'objets.

Cependant, les concepteurs ont pris soin de préserver la dynamique et la flexibilité du scriptage shell grâce à ce qu'ils appellent un "système d'exploitation". Système de type adaptatif .

Bref, je ne veux pas transformer ça en une publicité pour PowerShell. Il y a plein de choses qui sont no La plupart d'entre elles ont trait soit à Windows, soit à l'implémentation spécifique, et pas tellement aux concepts. (Par exemple, le fait qu'il soit implémenté en .NET signifie que le tout premier démarrage du shell peut prendre plusieurs secondes si le framework .NET n'est pas déjà dans le cache du système de fichiers à cause d'une autre application qui en a besoin. Si l'on considère que vous utilisez souvent le shell pendant bien moins d'une seconde, c'est totalement inacceptable).

Le point le plus important que je veux souligner est que si vous voulez examiner les travaux existants dans les langages de script et les shells, vous ne devez pas vous arrêter à Unix et à la famille Ruby/Python/Perl/PHP . Par exemple, Tcl a déjà été mentionné. Rexx serait un autre langage de script. Emacs Lisp en serait une autre. Et dans le domaine des interpréteurs de commandes, il y a certains des interpréteurs de commandes mainframe/midrange déjà mentionnés, comme la ligne de commande OS/400 et DCL. Et aussi, rc.

57voto

SFEley Points 4161

C'est culturel. Le site shell Bourne a presque 25 ans ; c'était l'un des premiers langages de script, et c'était la première bon une solution au besoin central des administrateurs Unix (c'est-à-dire une "colle" pour lier tous les autres utilitaires ensemble et pour effectuer les tâches typiques d'Unix sans avoir à compiler un fichu programme C à chaque fois).

Selon les normes modernes, sa syntaxe est atroce et ses règles bizarres ainsi que son style de ponctuation en tant qu'énoncé (utile dans les années 1970 lorsque chaque octet comptait) rendent difficile sa pénétration par des non-administrateurs. Mais il a fait le travail. Les défauts et les lacunes ont été corrigés par des améliorations évolutives dans ses descendants (ksh, bash, zsh) sans qu'il soit nécessaire de repenser les idées sous-jacentes. Les administrateurs sont restés fidèles à la syntaxe de base car, aussi bizarre que cela puisse être, rien d'autre ne gérait mieux les choses simples sans se mettre en travers.

Pour les choses complexes, Perl est arrivé et s'est transformé en une sorte de langage mi-administrateur, mi-application. Mais plus une chose est complexe, plus elle est considérée comme une application plutôt que comme un travail d'administration, de sorte que les responsables commerciaux ont tendance à rechercher des "programmeurs" plutôt que des "administrateurs" pour le faire, malgré le fait que le bon type de geek a tendance à être les deux. C'est donc là que l'accent a été mis, et les améliorations évolutives des capacités d'application de Perl ont donné naissance à... eh bien, Python et Ruby. (C'est une simplification excessive, mais Perl a été l'une des nombreuses inspirations de ces deux langages).

Résultat ? Spécialisation. Les administrateurs ont tendance à penser que les langages interprétés modernes sont trop lourds pour les tâches qu'ils sont payés à faire tous les jours. Et dans l'ensemble, ils ont raison. Ils n'ont pas besoin d'objets. Ils ne se soucient pas des structures de données. Ils ont besoin de des commandes. Ils ont besoin colle. Rien d'autre n'essaie de faire commandes mieux que le concept de l'interpréteur de commandes Bourne (sauf peut-être Tcl, qui a déjà été mentionné ici) ; et Bourne est suffisamment bon.

Les programmeurs, qui doivent aujourd'hui se familiariser de plus en plus avec le devops, regardent les limites du shell Bourne et se demandent comment on peut bien s'en accommoder. Mais les outils qu'ils connaissent, bien qu'ils penchent certainement vers le style Unix d'E/S et d'opérations sur les fichiers, ne sont pas des outils de gestion des données. meilleur dans ce but. J'ai écrit des choses comme des scripts de sauvegarde scripts et des renommages de fichiers en Ruby, parce que je le connais mieux que bash, mais n'importe quel administrateur dédié pourrait faire la même chose en bash --. probablement en moins de lignes et avec moins de frais généraux, mais dans tous les cas, ça marcherait aussi bien.

Il est fréquent de se demander "Pourquoi tout le monde utilise-t-il Y quand Z est meilleur ?" -- mais l'évolution de la technologie, comme l'évolution de tout le reste, a tendance à s'arrêter à assez bien. La "meilleure" solution ne l'emporte pas si la différence n'est pas perçue comme une frustration qui brise l'accord. Un script de type Bourne peut être frustrant pour vous Mais pour les personnes qui l'utilisent en permanence et pour les tâches pour lesquelles il a été conçu, il a toujours fait le travail.

52voto

Ivo van der Wijk Points 7239

Un langage shell doit être facile à utiliser. Vous voulez taper des commandes uniques, pas des petits programmes. Par exemple, vous voulez taper

ls -laR /usr

no

shell.ls("/usr", long=True, all=True, recursive=True)

Cela signifie (également) que les langages shell ne se soucient pas vraiment de savoir si un argument est une option, une chaîne, un nombre ou autre chose.

De plus, les constructions de programmation dans les shells sont un ajout, et ne sont même pas toujours intégrées. Par exemple, considérez la combinaison de si y [ dans (ba)sh, seq pour générer des séquences, et ainsi de suite.

Enfin, les coquillages ont des besoins spécifiques dont vous avez moins besoin, ou différemment dans la programmation. Par exemple, les tuyaux, la redirection des fichiers, le contrôle des processus/travaux, etc.

42voto

slebetman Points 28276

Si vous connaissez une telle langue, veuillez l'afficher également.

Tcl est l'un de ces langages. Principalement parce qu'il est conçu pour être avant tout un interpréteur de shell pour les programmes de CAO. Voici l'expérience d'un programmeur Python pur et dur* qui a compris pourquoi Tcl a été conçu de cette façon : http://www.yosefk.com/blog/i-cant-believe-im-praising-tcl.html

Pour ma part, j'ai écrit et utilisé un shell tcl amélioré (écrit en tcl bien sûr) comme principal shell de connexion Linux sur mon routeur homebrew : Pure tcl readline

Certaines des raisons pour lesquelles j'aime tcl en général ont tout à voir avec la similitude de sa syntaxe avec les shells traditionnels :

  1. Dans sa forme la plus simple, la syntaxe tcl est la suivante command argument argument... . Il n'y a rien d'autre. C'est la même chose que bash, csh ou même DOS shell.

  2. Un mot nu est considéré comme une chaîne de caractères. Ceci est à nouveau similaire aux shells traditionnels permettant d'écrire : open myfile.txt w+ au lieu de open "myfile.txt" "w+" .

  3. Grâce aux fondements de 1 et 2, tcl se retrouve avec très peu de syntaxe superflue. Vous écrivez du code avec moins de ponctuation : puts Hello au lieu de printf("Hello"); . Lorsque vous écrivez des programmes, vous ne ressentez pas autant la douleur car vous passez beaucoup de temps à réfléchir à ce que vous allez écrire. Lorsque vous utilisez un shell pour copier un fichier, vous ne pensez pas qu'il vous suffit de taper et de devoir taper ( y " y , y ) y ; encore et encore devient très vite ennuyeux.

*Note : pas moi, je suis un programmeur tcl hardcore

18voto

Chas. Owens Points 40887

Qui dit qu'ils ne le sont pas ? Jetez un coup d'œil à Zoidberg . REPLs (Boucles de lecture, d'évaluation et d'impression) font des shells merdiques parce que chaque commande doit être syntaxiquement correcte, et l'exécution d'un programme passe de l'état de :

foo arg1 arg2 arg3

a

system "foo", "arg1", "arg2", "arg3"

Et ne me laissez pas commencer à essayer de faire de la redirection.

Vous avez donc besoin d'un shell personnalisé (plutôt qu'un REPL) qui comprend les commandes et la redirection, ainsi que le langage que vous souhaitez utiliser pour lier les commandes entre elles. Je pense que zoid (la coquille Zoidberg) fait un assez bon travail.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X