Complication des commandes de la console, 1979-2020

Mon hobby est d'ouvrir la «philosophie UNIX» de McIlroy sur un moniteur tout en lisant du mana sur un autre.

Le premier des principes de McIlroy est souvent reformulé comme «Faites une chose, mais faites bien.» Il s'agit d'une abréviation pour ses mots, "Créez des programmes qui font bien une chose." Pour de nouveaux travaux, créez de nouveaux programmes, plutôt que de compliquer les anciens en ajoutant de nouvelles "fonctions". »

McIlroy donne un exemple:

Il semble surprenant aux étrangers que les compilateurs UNIX n'émettent pas de listes: l'impression est mieux effectuée et configurée de manière plus flexible à l'aide d'un programme distinct.

Si vous ouvrez l'aide pour ls, cela commence par

ls [-ABCFGHLOPRSTUW@abcdefghiklmnopqrstuwx1] [file ...]

Autrement dit, les indicateurs à une lettre pour lsincluent toutes les lettres minuscules, à l'exception de {jvyz}14 lettres majuscules, @et 1. Il s'agit de 22 + 14 + 2 = 38 uniquement des options à un seul caractère.

Dans Ubuntu 17, l'aide de lsn'affichera pas de résumé normal, mais vous verrez qu'il lsy a 58 options (y compris --helpet --version).

Voyons s'il s'agit d'une situation unique ou d'une situation normale. Faisons une liste de quelques commandes courantes, triées par fréquence d'utilisation.



Le tableau indique le nombre d'options de ligne de commande pour diverses commandes v7 Unix (1979), slackware 3.1 (1996), ubuntu 12 (2015) et ubuntu 17 (2017). Plus il y a de paramètres, plus les cellules sont sombres (sur une échelle logarithmique).

Nous constatons qu'au fil des années, le nombre d'options augmente considérablement: en règle générale, les enregistrements s'assombrissent de gauche à droite (plus d'options), et il n'y a aucun cas où les enregistrements deviennent plus légers (moins d'options).

McIlroy a longtemps condamné l' augmentation du nombre d'options, la taille et la fonctionnalité globale des équipes 1:

, , Linux … []. , , . , , … Unix : « ? ?» , - , . , , , . … , .

Ironiquement, l'une des raisons du nombre croissant d'options de ligne de commande est l'autre dicton de McIlroy: «Écrivez des programmes pour traiter les flux de texte car c'est une interface universelle» (voir à lstitre d'exemple).

Si des données ou des objets structurés ont été transmis, le formatage peut être laissé à l'étape finale. Mais dans le cas du texte brut, la mise en forme et le contenu sont mélangés; comme le formatage ne peut être effectué qu'en analysant le contenu, les commandes ajoutent généralement des options de formatage pour plus de commodité. De plus, le format peut être effectué lorsqu'un utilisateur applique sa connaissance de la structure de données, et « encode » la connaissance des arguments pour cut, awk,sedetc. (l'utilisateur utilise également sa connaissance de la façon dont ces programmes fonctionnent avec le formatage, car il est différent pour différents programmes, donc l'utilisateur doit savoir, par exemple, en quoi il cut -f4 diffère de awk '{ print $4 }2) C'est beaucoup plus compliqué que de passer un ou deux arguments à la commande suivante dans une séquence, ce qui transfère la complexité de l'outil à l'utilisateur.

Les gens disent parfois qu'ils ne veulent pas prendre en charge les données structurées, car alors, dans un outil universel, il faudrait prendre en charge plusieurs formats. Mais ils doivent déjà prendre en charge plusieurs formats pour en faire un outil universel. Certaines commandes standard ne peuvent pas lire la sortie d'autres commandes car elles utilisent des formats différents. Par exemple, wc -wUnicode ne le gère pas correctement, etc. Dire que «texte» est un format universel revient à dire que «binaire» est un format universel.

On dit qu'il n'y a pas d'alternative à une telle complication des outils de ligne de commande. Mais les gens qui disent cela n'ont jamais essayé d'alternative, quelque chose comme PowerShell. J'ai de nombreuses plaintes concernant PowerShell, mais le transfert de données structurées et la possibilité de travailler facilement avec des données structurées sans avoir à garder les métadonnées en tête afin que je puisse les transférer vers les bons outils de ligne de commande aux bons endroits sur le pipeline ne fait pas partie de mes plaintes 3.

Lorsque l'on vous dit que les programmes doivent être simples et compatibles lors du traitement du texte, ces personnes prétendent que les données textuelles n'ont pas de structure à analyser 4. Dans certains cas, nous pouvons tout considérer comme une seule ligne, séparés par des espaces, ou comme un tableau avec des séparateurs de lignes et de colonnes ( avec un comportement qui, bien sûr, n'est pas cohérent avec d'autres outils ). Cela ajoute un peu de mal. Il existe encore des cas où la sérialisation des données dans un format de texte brut ajoute une complexité importante, car en raison de la structure des données, une simple sérialisation au texte nécessite par la suite d'importants efforts d'analyse pour réassimiler les données de manière significative.

Une autre raison pour laquelle les équipes ont désormais plus d'options est que les gens ont ajouté des indicateurs pratiques pour les fonctionnalités qui pourraient être implémentées par un pipeline de plusieurs équipes. Cette pratique se poursuit depuis Unix v7, où danslsune option a semblé changer l'ordre de tri (bien que cela puisse être fait en passant la sortie à tac).

Au fil du temps, uniquement pour des raisons de commodité, des paramètres supplémentaires ont été ajoutés. Par exemple, une commande mvqui était à l'origine sans paramètres peut désormais déplacer le fichier et créer simultanément une copie de sauvegarde (trois options; deux façons différentes de spécifier une sauvegarde, dont l'une prend un argument et l'autre ne prend aucun argument, lit un argument implicite à partir d'une variable d'environnement VERSION_CONTROL; une autre option vous permet de remplacer le suffixe de sauvegarde par défaut). Il mvexiste maintenant des options pour ne jamais écraser les fichiers ou écraser uniquement les fichiers plus récents.

mkdirun autre programme qui n'avait auparavant aucune option. Aujourd'hui, tous ses indicateurs, à l'exception des options de sécurité pour SELinux ou SMACK, ainsi que les numéros d'aide et de version, sont ajoutés uniquement pour des raisons de commodité: définir des autorisations pour le nouveau répertoire et créer des répertoires parents s'ils n'existent pas.

Au taildébut, il n'y avait qu'une seule option -number, indiquant le point de départ du travail. Ensuite, nous avons ajouté à la fois le formatage et les options pour la commodité du formatage. Le drapeau -zremplace le séparateur de ligne par null. Voici d'autres exemples d'options ajoutées pour plus de commodité: -fpour imprimer lorsque de nouvelles modifications apparaissent, -spour définir l'intervalle de temps entre la vérification des modifications / code> -f, et -retrypour réessayer d'accéder au fichier s'il n'est pas disponible.

McIlroy reproche aux développeurs d'avoir ajouté toutes ces options, mais personnellement, je me sens mieux. Bien que je n'en ai jamais utilisé certains, j'en ai rarement utilisé d'autres, mais c'est la beauté des paramètres de ligne de commande - contrairement à l'interface graphique, l'ajout de ces paramètres n'encombre pas l'interface. Oui, le mana et l'aide gonflent, mais à l'ère de Google et de Stackoverflow, dans tous les cas, beaucoup se contentent de rechercher n'importe quelle question sur Google, plutôt que de lire du mana.

Bien sûr, l'ajout d'options augmente la charge des mainteneurs. Mais c'est un juste paiement pour les avantages qu'ils apportent. Étant donné le rapport entre le nombre de mainteneurs et d'utilisateurs, il est logique d'imposer une charge supplémentaire aux premiers, et non aux seconds. Ceci est similaire à la remarque de Gary Bernhardt selon laquelle il est raisonnable de répéter une performance 50 fois. Si l'audience est de 300 personnes, le rapport entre le temps passé à regarder la représentation et le temps consacré aux répétitions sera toujours de 6: 1. Pour les outils de ligne de commande populaires, ce rapport est encore plus extrême.

Certains pourraient faire valoir que toutes ces options supplémentaires font peser une charge supplémentaire sur les utilisateurs. Ce n'est pas tout à fait faux, mais ce fardeau de complexité existera toujours. La question est de savoir où exactement. Si vous imaginez qu'un ensemble d'outils de ligne de commande avec un shell forme un langage dans lequel tout le monde peut écrire une nouvelle méthode, et en cas de popularité, la méthode est effectivement ajoutée à la bibliothèque standard, et les normes sont déterminées par des axiomes comme «Écrire des programmes pour traiter des flux de texte, car c'est universel interface ", alors le langage se transformera en un chaos incohérent en écriture seule, si vous le prenez dans son intégralité. Au moins, grâce à des outils avec une large gamme d'options et de fonctionnalités, les utilisateurs d'Unix peuvent remplacer un ensemble géant d'outils extrêmement incohérents par juste un grand ensemble d'outils qui,bien qu'ils soient incompatibles de l'extérieur, ils ont une certaine cohérence interne.

McIlroy implique un manque de réflexion dans la boîte à outils. Par exemple, les pères fondateurs d'Unix devraient s'asseoir dans la même pièce et réfléchir soigneusement jusqu'à ce qu'ils trouvent un ensemble d'outils séquentiels d'une «simplicité extraordinaire». Mais il ne s'agrandira pas, la philosophie d'Unix elle-même a inévitablement conduit au gâchis dans lequel nous sommes. Ce n'est pas que quelqu'un n'a pas réfléchi longtemps ou durement. Il s'agit d'une philosophie qui ne s'étend pas au-delà d'une équipe relativement petite avec une compréhension culturelle commune qui peut tenir dans une seule pièce.

Si quelqu'un veut écrire un outil basé sur la «philosophie Unix», différentes personnes auront des opinions différentes sur ce que signifie «simplicité» ou le principe de «faire une chose» 5comment l'outil devrait fonctionner correctement - et l'incohérence se développera dans une couleur luxuriante, résultant en une énorme complexité similaire aux langages extrêmement incohérents comme PHP. Les gens se moquent de PHP et de JavaScript pour diverses bizarreries et incohérences, mais comme un langage et une bibliothèque standard, tout shell populaire avec une collection d'outils * nix populaires, pris ensemble, est bien pire et contient une complexité beaucoup plus aléatoire en raison d'incohérences même au sein de la même distribution Linux . Il ne peut en être autrement. Si vous comparez les distributions de Linux, BSD, Solaris, AIX, etc., la quantité de complexité aléatoire que les utilisateurs doivent garder à l'esprit lors du changement de système, éclipse l'incohérence de PHP ou JavaScript.Les langages de programmation les plus largement ridiculisés sont de véritables exemples de grande conception par rapport à eux.

Pour plus de clarté, je ne dis pas que moi-même ou quelqu'un d'autre pourrait mieux faire face au développement dans les années 70, en tenant compte des connaissances disponibles à l'époque, et créer un système qui serait à la fois utile à l'époque et élégant aujourd'hui. Bien sûr, il est facile de regarder en arrière et de trouver des problèmes rétrospectivement. Je suis tout simplement en désaccord avec les commentaires de certains connaisseurs d'Unix, comme McIlroy, qui suggèrent que nous avons oublié ou ne comprenons pas la valeur de la simplicité. Ou Ken Thompson, qui dit que C est un langage aussi sûr que n'importe quel autre, et si nous ne voulons pas que des erreurs apparaissent, nous avons juste besoin d'écrire du code sans erreurs. Des commentaires de ce genre impliquent que peu de choses ont changé au fil des ans. Apparemment, dans les années 70, nous avons construit des systèmes de la même manière qu'aujourd'hui, et pendant cinq décennies d'expérience collective, des dizaines de millions d'années-personnes ne nous ont rien appris. Et si nous nous tournons vers les origines, vers les créateurs d'Unix, alors tout ira bien. Avec tout le respect que je vous dois, je ne suis pas d'accord.

Application: mémoire


Bien que les plaintes de McIlroy concernant les binaires de ballonnement soient un peu en dehors de la portée de cet article, je noterai qu'en 2017, j'ai acheté un Chromebook avec 16 Go de RAM pour 300 $. Le binaire de 1 mégaoctet pourrait être un problème grave en 1979, lorsque l'Apple II standard était équipé de 4 kilo-octets de mémoire. Apple II a coûté 1298 $ en 1979, ou 4612 $ en 2020. Aujourd'hui, vous pouvez acheter un Chromebook peu coûteux qui coûte moins de 1/15 de ce prix, alors qu'il a quatre millions de fois plus de mémoire. Les plaintes selon lesquelles l'utilisation de la mémoire a augmenté mille fois semblent un peu ridicules lorsque (portable!) La machine coûte un ordre de grandeur moins cher et dispose de quatre millions de fois plus de mémoire.

J'aime l'optimisation, j'ai donc réduit ma page d'accueil à deux packages (il y en aurait un si le CDN supportait brotli de haut niveau), mais c'est une exigence purement esthétique, je le fais pour le plaisir. Le goulot d'étranglement des outils de ligne de commande n'utilise pas de mémoire, et le temps d'optimiser la mémoire de l'outil avec une taille d'un mégaoctet revient à réduire une page d'accueil à un seul package. Peut-être un passe-temps amusant, mais rien de plus.

Méthodologie de compilation des tableaux


La fréquence d'utilisation des commandes est obtenue à partir des fichiers publics de l'historique des commandes sur github, elle ne correspond pas nécessairement à votre expérience personnelle. Seules les commandes "simples" ont été comptées, à l'exclusion des instances comme curl, git, gcc (ce dernier a plus de 1000 options) et wget. Le concept de simplicité est relatif. Les commandes shell intégrées , telles que cd, n'étaient pas non plus prises en compte.

La répétition des drapeaux n'était pas considérée comme une option distincte. Par exemple, u git blame -C, git blame -C -Cet git blame -C -C -Cun comportement différent, mais ils seront tous considérés comme un seul argument, bien qu'il -C -Cs'agisse en -C réalité d'arguments différents.

Les sous-options du tableau sont comptées comme une option. Par exemple, il lsprend en charge les éléments suivants:

--format=WORD across -x, commas -m, horizontal -x, long -l, single-column -1, verbose -l, vertical -C

Malgré sept options format, cela compte comme une option.

Les options qui sont explicitement indiquées comme inutiles sont toujours considérées comme des options, par exemple ls -g, qui est ignoré est également considéré.

Plusieurs versions de la même option sont considérées comme une seule option. Par exemple, -Aet --almost-allpour ls.

Si le certificat indique que l'option existe, mais qu'en réalité elle n'existe pas, alors elle n'est pas prise en compte. Par exemple, l'aide pour v7 mv indique:

SACS

Si fichier1 et fichier2 sont dans des systèmes de fichiers différents, alors mv doit copier le fichier et supprimer l'original. Dans ce cas, le nom du propriétaire devient le nom du processus de copie et toute connexion avec d'autres fichiers est perdue.

mv doit accepter l'indicateur -f comme rm afin de supprimer un message sur l'existence d'un fichier cible qui n'est pas accessible en écriture.

Mais -fil n'est pas considéré comme un indicateur dans le tableau, car l'option n'existe pas réellement.

Le tableau se termine en 2017 car le premier projet de cet article a ensuite été rédigé. Ce n'est que maintenant qu'ils ont pu le lire.

Sur ce sujet



, , -, //.



1. Cette citation est légèrement différente de la version courante car j'ai regardé la vidéo originale . Pour autant que je sache, toutes les copies de cette citation sur Internet (index Bing, DuckDuckGo et Google) sont extraites de la même transcription d'une personne. Il y a une certaine ambiguïté, car le son est de mauvaise qualité et j'entends des mots légèrement différents de ce que cette personne a entendu. [rendre]

2. Un autre exemple de la façon dont la complexité est transmise à l'utilisateur, car différentes équipes gèrent le formatage différemment, est le formatage temporel . Le temps shell intégré est time, bien sûr, incompatible avec /usr/bin/time. L'utilisateur doit être conscient de ce fait et savoir comment le gérer. [rendre]

3. Par exemple, pour tout objet que vous pouvez utiliser ConvertTo-Jsonou ConvertTo-CSV. Ou «applets de commande» pour modifier l'affichage des propriétés de l'objet . Vous pouvez écrire des fichiers de configuration de formatage qui définissent vos méthodes de formatage préférées.

Une autre façon de voir les choses est à travers le prisme de la loi de Conway . Si nous avons un ensemble d'outils de ligne de commande créés par différentes personnes, souvent de différentes organisations, ces outils seront extrêmement incohérents si quelqu'un ne peut pas déterminer la norme et forcer les gens à l'accepter. Cela fonctionne en fait relativement bien sous Windows, pas seulement avec PowerShell.

Une plainte courante contre Microsoft est le chiffre d'affaires massif de l'API, souvent pour des raisons organisationnelles non techniques (par exemple, voir les actions de Stephen Sinofsky décrites dans les réponses à un tweet à distance ). C'est vrai. Cependant, du point de vue d'un utilisateur naïf, le logiciel Windows standard, en règle générale, transmet des données non textuelles bien mieux que * nix. La couverture des données non textuelles dans Windows remonte au moins à COM en 1999 (et éventuellement à OLE et DDE, publiées respectivement en 1990 et 1987).

Par exemple, si vous copiez depuis Foo, qui prend en charge le format binaire Aet Bdans la barre, qui prend en charge les formats B, Cpuis copiez de Bar vers Baz, qui prend en charge CetD, tout fonctionnera bien, même si Foo et Baz n'ont pas de formats pris en charge communs.

Lorsque vous coupez ou copiez quelque chose, l'application «indique» essentiellement au presse-papiers dans quels formats elle peut fournir des données. Une fois collée dans une application, l'application finale peut demander des données dans l'un des formats disponibles. Si les données sont déjà dans le presse-papiers, Windows les fournit. Si ce n'est pas le cas, Windows reçoit les données de l'application source, puis les transfère vers l'application cible et une copie est stockée pendant un certain temps. Si vous «coupez» d'Excel, il vous dira «qu'il» a des données disponibles dans plusieurs dizaines de formats. Un tel système est assez bon pour la compatibilité, bien qu'il ne puisse certainement pas être qualifié de simple ou minimaliste.

En plus de la bonne prise en charge de nombreux formats, il est suffisamment long pour que de nombreux programmes commencent à bien gérer ces fonctionnalités; sous Windows, le support du presse-papiers est généralement bon.

Supposons que vous copiez et collez une petite quantité de texte. Dans la plupart des cas, aucune surprise ne se produira sous Windows ou Linux. Supposons maintenant que vous ayez copié du texte, fermé le programme à partir duquel vous avez copié, puis collé. De nombreux utilisateurs ont tendance à penser que lors de la copie des données sont stockées dans le presse-papiers, et non dans le programme à partir duquel elles sont copiées. Sous Windows, les logiciels sont généralement écrits en fonction de cette attente (bien que techniquement les utilisateurs de l'API du presse-papiers ne devraient pas le faire). Ceci est moins courant sous Linux avec X, où le modèle mental correct pour la plupart des programmes est que la copie enregistre un pointeur sur les données qui appartiennent toujours au programme à partir duquel elles sont copiées. Autrement dit, l'insertion ne fonctionnera pas si le programme est fermé.Lorsque j'ai (informellement) interviewé des programmeurs, ils étaient généralement surpris de cela, à moins qu'ils ne travaillent vraiment avec la fonction copier-coller pour leur application. Lorsque j'ai interviewé des non-programmeurs, ils ont généralement trouvé ce comportement non seulement surprenant, mais aussi déroutant.

L'inconvénient du transfert du presse-papiers vers le système d'exploitation est que la copie de grandes quantités de données coûte cher. Supposons que vous copiez une très grande quantité de texte, beaucoup de gigaoctets ou une sorte d'objet complexe, puis ne le collez pas. En fait, vous ne souhaitez pas copier ces données de votre programme vers le système d'exploitation afin qu'elles soient stockées et disponibles. Windows le fait judicieusement: les applications ne peuvent fournir des données à la demande que si elles sont jugées utiles. Dans notre cas, lorsque l'utilisateur ferme le programme, il peut déterminer s'il faut mettre des données dans le presse-papiers ou les supprimer. Dans ce cas, de nombreux programmes (par exemple, Excel) proposent de «sauvegarder» des données dans le presse-papiers ou de les supprimer, ce qui est tout à fait raisonnable.

Certaines de ces fonctionnalités peuvent être implémentées sous Linux. Par exemple,La spécification ClipboardManager décrit le mécanisme de sauvegarde et les applications GNOME le prennent généralement en charge (quoique avec quelques bogues ), mais la situation sur * nix diffère vraiment de la prise en charge omniprésente des applications Windows, où un presse-papier compétent est généralement implémenté. [rendre]

4. Un autre exemple est les outils au-dessus des compilateurs modernes. Revenons en arrière et examinons l'exemple canonique de Macilroy, où les bons compilateurs Unix sont si spécialisés que la liste est effectuée par un outil distinct. Mais aujourd'hui, cela a changé, même si un outil de référencement séparé est resté. Certains compilateurs Linux populaires ont littéralement des milliers d'options - et ils sont extrêmement riches en fonctionnalités. Par exemple, l'une des nombreuses fonctions du moderne clang est l'analyse statique. Au moment d'écrire ces lignes, il existe 79 tests de routine d'analyse statique et 44 tests expérimentaux.. S'il s'agissait de commandes distinctes, elles s'appuieraient toujours sur la même infrastructure de base du compilateur et imposeraient la même charge de maintenance - il est en fait déraisonnable que ces outils d'analyse statique fonctionnent avec du texte brut et redéfinissent l'ensemble de la chaîne d'outils du compilateur nécessaire pour obtenir le point où ils peuvent effectuer une analyse statique. Ils peuvent être des commandes distinctes au lieu d'être combinés en clang, mais ils dépendront toujours du même mécanisme et imposeront la charge de la maintenance et de la complexité au compilateur (qui devrait prendre en charge des interfaces stables pour les outils qui fonctionnent par-dessus), ou ils seront constants Pause.

Faire tout dans le texte pour plus de simplicité semble beau, mais en fait, la représentation textuelle des données n'est souvent pas ce dont vous avez besoin si vous voulez faire un travail vraiment utile.

Le même clang est tout simplement plus fonctionnel que n'importe quel compilateur qui existait en 1979, ou même tous les compilateurs qui existaient en 1979 combinés, qu'il soit exécuté par une commande monolithique ou par des milliers d'instructions plus petites. Il est facile de dire qu'en 1979 tout était plus simple et que nous, programmeurs modernes, nous sommes égarés. Mais en réalité, il est difficile d'offrir un design beaucoup plus simple et vraiment accepté par tout le monde. Il est impossible qu'une telle conception puisse préserver toutes les fonctionnalités et configurabilité existantes et être aussi simple que quelque chose de 1979. [rendre]

5. Depuis sa création, curl est passé de la prise en charge de trois protocoles à 40. Est-ce à dire qu'il «fait 40 choses» et la philosophie Unix exige-t-elle qu'elle soit divisée en 40 commandes distinctes? Cela dépend de qui demander. Si chaque protocole était sa propre équipe, créé et soutenu par une autre personne, nous aurions le même bordel qu'avec les équipes. Paramètres de ligne de commande incohérents, formats de sortie incohérents, malgré le fait que ce sont tous des flux de texte, etc. Cela nous rapproche-t-il de la simplicité que préconise McIlroy? Cela dépend de qui demander. [rendre]

All Articles