web-dev-qa-db-fra.com

one-liner vs script

J'ai remarqué beaucoup de questions et réponses et de commentaires exprimant du dédain pour (et parfois même la peur de) écrire des scripts au lieu d'une ligne. Je voudrais donc savoir:

  • Quand et pourquoi devrais-je écrire un script autonome plutôt qu'un "one-liner"? Ou vice versa?

  • Quels sont les cas d'utilisation et les avantages et inconvénients des deux?

  • Certaines langues (par exemple awk ou Perl) sont-elles mieux adaptées aux lignes simples que d'autres (par exemple python)? Si oui, pourquoi?

  • S'agit-il simplement d'une préférence personnelle ou existe-t-il de bonnes raisons (c'est-à-dire objectives) d'écrire l'une ou l'autre dans des circonstances particulières? Quelles sont ces raisons?

Définitions

  • one-liner: toute séquence de commandes tapées ou collées directement dans une ligne de commande Shell. Impliquant souvent des pipelines et/ou l'utilisation de langages tels que sed, awk, Perl et/ou des outils comme grep ou cut ou sort.

    C'est l'exécution directe sur la ligne de commande qui est la caractéristique qui définit - la longueur et le formatage ne sont pas pertinents. Un "one-liner" peut être tout sur une seule ligne, ou il peut avoir plusieurs lignes (par exemple sh pour boucle, ou code awk ou sed intégré, avec des sauts de ligne et une indentation pour améliorer la lisibilité).

  • script: toute séquence de commandes dans n'importe quel langage interprété qui sont enregistrées dans un fichier, puis exécutées. Un script peut être écrit entièrement dans une langue, ou il peut être un wrapper de script Shell autour de plusieurs "one-liners" utilisant d'autres langues.


J'ai ma propre réponse (que je posterai plus tard), mais je veux que cela devienne un Q&A canonique sur le sujet, pas seulement mon opinion personnelle.

25
cas

Une autre réponse basée sur l'expérience pratique.

J'utiliserais un one-liner si c'était du code "jetable" que je pourrais écrire directement à l'invite. Par exemple, je pourrais utiliser ceci:

for h in Host1 Host2 Host3; do printf "%s\t%s\n" "$h" "$(ssh "$h" uptime)"; done

J'utiliserais un script si je décidais que le code valait la peine d'être sauvegardé. À ce stade, j'ajouterais une description en haut du fichier, ajouterais probablement une vérification des erreurs, et peut-être même la vérifier dans un référentiel de code pour le versionnement. Par exemple, si je décidais que la vérification du temps de disponibilité d'un ensemble de serveurs était une fonction utile que j'utiliserais encore et encore, le one-liner ci-dessus pourrait être étendu à ceci:

#!/bin/bash
# Check the uptime for each of the known set of hosts
########################################################################
#
hosts=(Host1 Host2 Host3)

for h in "${hosts[@]}"
do
    printf "%s\t" "$h"
    uptime=$(ssh -o ConnectTimeout=5 -n "$h" uptime 2>/dev/null)
    printf "%s\n" "${uptime:-(unreachable)}"
done

Généralisant, on pourrait dire

  • Bon mot

    • Code simple (c'est-à-dire juste "quelques" instructions), écrit dans un but spécifique unique
    • Code qui peut être écrit rapidement et facilement chaque fois qu'il est nécessaire
    • Code jetable
  • Scénario

    • Code qui sera (probablement) utilisé plus d'une ou deux fois
    • Code complexe nécessitant plus que "quelques" instructions
    • Code qui devra être maintenu par d'autres
    • Code à comprendre par les autres
    • Code à exécuter sans assistance (par exemple, à partir de cron)

Je vois un bon nombre de questions ici sur nix.SE demander un one-liner pour effectuer une tâche particulière. En utilisant mes exemples ci-dessus, je pense que le second est beaucoup plus compréhensible que le premier, et donc les lecteurs peuvent en apprendre davantage. Une solution peut être facilement dérivée de l'autre, donc dans un souci de lisibilité (pour les futurs lecteurs), nous devrions probablement éviter de fournir du code coincé sur une seule ligne pour autre chose que la plus triviale des solutions.

33
roaima

Écrivez un script lorsque:

  • plus de code est requis
  • vous appréciez la lisibilité
  • il est nécessaire/utile d'ajouter des commentaires, de montrer ce que fait le code
  • vous devez passer des paramètres
  • vous voulez que le script s'exécute dans son propre environnement (variables, etc.)
  • vous allez probablement réutiliser/adapter le code à des fins plus complexes

Écrivez un one-liner lorsque:

  • seule une petite quantité de code est nécessaire
  • vous souhaitez accéder aux variables définies dans le shell actuel
  • vous avez besoin d'une solution rapide et sale
10
dr_

Lorsqu'une série de commandes requise est assez courte et/ou produit un résultat qui pourrait être utilisable dans le cadre d'un pipeline plus grand ou d'un alias de commande, il peut s'agir d'une bonne ligne unique.

Fondamentalement, je pense que les monolignes sont généralement des choses qu'un administrateur système chevronné connaissant à la fois le problème et les commandes utilisées peut écrire sur place, sans trop réfléchir.

Quand une ligne devient excessivement longue ou implique plus que des conditions ou des boucles très simples, il est généralement préférable de les écrire sous forme de script multi-lignes ou de fonction Shell, pour plus de lisibilité. De plus, si c'est quelque chose que vous écrivez pour être utilisé encore et encore, ou quelque chose qui sera utilisé (et éventuellement dépanné) par d'autres personnes, vous devriez être prêt à passer le temps d'écrire la solution dans un langage clair (er), a commenté, formulaire de script.

En Python, l'indentation fait partie de la syntaxe, donc vous ne pouvez littéralement pas utiliser pleinement les fonctionnalités du langage si vous écrivez une seule ligne.

Les lignes simples Perl et awk consistent souvent à utiliser la puissance brute des expressions régulières. Mais certains appellent les expressions régulières un langage en écriture seule, pas entièrement sans raison. L'écriture d'un script multi-lignes vous permet d'écrire dans des commentaires pour décrire ce qu'une expression régulière particulière est censée faire, ce qui sera très utile lorsque vous relisez le script, après avoir fait autre chose pendant six mois entre les deux.

Il s'agit d'une question intrinsèquement très fondée sur l'opinion, car elle implique d'évaluer la complexité acceptable et les compromis entre lisibilité et compacité; toutes ces questions relèvent essentiellement du jugement personnel. Même le choix d'une langue peut dépendre de questions personnelles: si une langue particulière est théoriquement optimale pour un problème particulier, mais que vous ne la connaissez pas et savez déjà comment résoudre le problème avec une autre langue, vous pouvez choisir le langage familier afin de faire le travail rapidement et avec un minimum d'effort, bien que la solution puisse être techniquement quelque peu inefficace.

Le meilleur est souvent l'ennemi de assez bien, et cela s'applique très bien ici.

Et si vous connaissez Perl, vous avez peut-être déjà entendu parler de TMTOWTDI: Il y a plus d'une façon de le faire.

9
telcoM

Veuillez noter qu'il s'agit d'une opinion personnelle; Prenez-le avec un grain de sel.

  1. Si la commande tient dans, disons, 80 caractères, utilisez une ligne. Les longues lignes de commande sont difficiles à utiliser. Il y a aussi le problème de récidive, voir # 2

  2. Si vous devez exécuter la ou les commandes plusieurs fois, utilisez un script. Sinon, utilisez une doublure, à condition que la condition n ° 1 soit remplie.

  3. C'est très subjectif, mais oui, je vois Shell, Perl ou awk comme étant mes outils de prédilection pour les monolignes.
  4. Voir # 1, # 2, # 3.
7
schaiba

Je vois et j'utilise un one-liner comme un outil de développement temporaire pour éditer à plusieurs reprises jusqu'à ce qu'il fasse ce que je veux, ou je comprends comment fonctionne la subtilité d'une sous-commande.

Il est ensuite soit noté (et annoté) dans un fichier texte sur le sujet sur lequel j'étudiais, soit nettoyé dans un script qui est mis dans mon bac personnel PATH, éventuellement pour un raffinement, un paramétrage, etc. En règle générale, la ligne sera décomposée en plus lisible, même si aucune autre modification n'est apportée, ou si je n'utilise plus jamais le script.

J'ai défini mon historique Shell sur plus de 5 000 lignes, avec un historique distinct par terminal et par connexion sur une télécommande, etc. Je déteste ne pas être en mesure de trouver dans ces histoires une commande en ligne que j'ai développée il y a quelques semaines et que je ne pensais pas avoir besoin à nouveau, d'où ma stratégie.

Parfois, tout un groupe de commandes doit faire quelque chose, comme configurer du matériel; à la fin, je les copie tous de l'historique, les nettoie au minimum et les ajoute à un script Shell RUNME juste comme des notes sur ce que j'ai fait, mais aussi pour qu'ils soient presque prêts à être réutilisés par quelqu'un d'autre. (C'est pourquoi je trouve des outils qui ne fournissent qu'une interface graphique pour les configurer une telle douleur.) Je trouve cela un gain d'efficacité incroyable, car si souvent quelque chose que vous vous attendez à faire une seule fois, doit être fait encore 5 fois .. .

7
meuh

Je dois dire que je suis quelque peu horrifié par les implications des premières parties de la question. Les langages de script Unix sont des langages de programmation à part entière, et les langages de programmation sont langages, ce qui signifie qu'ils sont à peu près aussi infiniment malléables et flexibles que les langages humains. Et l'une des caractéristiques de "la malléabilité et la flexibilité infinies" est qu'il n'y a presque jamais "une bonne façon" d'exprimer quelque chose - il existe des variétés de façons, et c'est une bonne chose! Donc, oui, bien sûr c'est une question de préférence personnelle, et il n'y a rien de mal à cela. Quiconque dit qu'il n'y a qu'une seule façon de faire quelque chose, quiconque a exprimé son dédain de faire (ou de ne pas faire) quelque chose d'une façon ou d'une autre est probablement un pédant ou un prescriptiviste.

Il était une fois, mon propre ~/bin était complet des petits scripts "utiles" que j'avais écrits. Mais j'ai réalisé que la plupart d'entre eux étaient utilisés le jour où je les ai écrits, et plus jamais. Donc, plus le temps passe, plus mon répertoire bin est petit.

Je ne pense pas qu'il y ait quelque chose faux avec l'écriture d'un script. Si vous imaginez que vous ou quelqu'un d'autre pourriez l'utiliser à nouveau, écrivez certainement un script. Si vous voulez "correctement concevoir" un script supportable pour le plaisir, faites-le. (Même si personne ne l'utilise jamais, l'écrire est une bonne pratique.)

Raisons pour lesquelles je n'écris plus autant de scripts (et, je suppose, je préfère les "one-liners"):

  • bin l'encombrement du répertoire a un coût. Je ne mets plus de choses là-bas à moins qu'elles ne leur appartiennent vraiment.
  • Les langages de script que j'utilise sont des langages que je tilise; Je suis vraiment facile avec eux maintenant. Retaper un one-liner chaque fois que j'en ai besoin ne ressemble pas à du travail; Je ne me sens pas mandaté pour conserver et sauvegarder et utiliser un script juste pour soulager la charge de (re) frappe. (Entre autres choses, à un moment donné, le fardeau de retaper devient moins lourd que le fardeau de la mémoire de se rappeler ce qu'est un script.)
  • Une autre raison pour laquelle retaper les choses ne semble pas être un fardeau est: l'historique des commandes. Il y a beaucoup de lignes simples que je n'ai pas consacrées en tant que scripts, même si je les utilise tous les jours - mais je n'ai pas à les retaper; Je les rappelle juste de l'histoire. De cette façon, ils sont en quelque sorte des scripts ou des alias de pauvres.
5
Steve Summit

On dirait que j'ai une opinion minoritaire à ce sujet.

Le terme "script" est intentionnellement déroutant, débarrassez-vous-en. Ceci est un logiciel vous écrivez là-bas, même si vous utilisez uniquement bash et awk.

Au sein d'une équipe, je préfère écrire un logiciel avec un processus de révision de code appliqué par un outil (github/gitlab/gerrit). Cela donne un contrôle de version en prime. Si vous avez plusieurs systèmes, ajoutez des outils de déploiement continu. Et certaines suites de tests, si les systèmes cibles sont importants. Je ne suis pas religieux à ce sujet, mais je pèse les avantages et les coûts.

Si vous avez une équipe d'administrateurs, le plus simple vim /root/bin/x.sh est principalement une catastrophe en termes de communication liée au changement, de lisibilité du code et de distribution inter-systèmes. Souvent, un dysfonctionnement grave coûte plus de temps/d'argent que le processus soi-disant "lourd".

Je préfère les lignes simples en fait pour tout ce qui ne mérite pas ce processus "lourd". Ils peuvent être réutilisés rapidement, en quelques touches, si vous savez utiliser efficacement votre historique Shell; collé facilement entre des systèmes indépendants (par exemple, différents clients).

Différence cruciale entre les monolignes (non révisées!) Et les logiciels examinés ("scripts"): la responsabilité vous incombe entièrement lorsque vous exécutez des monolignes. Vous ne pouvez jamais vous dire "Je viens de trouver ce one-liner quelque part, je l'ai exécuté sans comprendre, ce qui a suivi n'est pas de ma faute" - vous saviez que vous exécutez un logiciel non révisé et non testé, donc il est votre faute. Assurez-vous qu'il est suffisamment petit pour que vous puissiez prévoir les résultats - soyez damné si vous ne le faites pas.

Vous avez parfois besoin de cette approche simpliste, et définir la barre sur environ une ligne de texte fonctionne bien dans la pratique (c'est-à-dire la frontière entre le code révisé et le code non révisé). Certains de mes uniformes ont l'air terriblement longs, mais ils fonctionnent efficacement pour moi. Tant que je les gâche et que je ne le pousse pas vers des collègues plus juniors, tout va bien. Le moment où j'ai besoin de les partager - je passe par le processus de développement de logiciels standard.

5
kubanczyk

Je souhaiterais que les membres de mon équipe écrivent des scripts pour toutes les opérations pouvant être exécutées plusieurs fois (par exemple, "workflows" ou "pipelines"), et pour toute tâche ponctuelle devant être documentée (généralement des choses comme "modifier certaines choses dans un ensemble de données pour corriger des données incorrectement fournies" dans notre cas). En dehors de cela, les "one-liners" ou les scripts n'ont pas trop d'importance.

Ne pas documenter correctement les flux de travail (sous forme de scripts ou équivalent), il est plus difficile d'introduire de nouveaux membres du personnel sur un projet, et rend également plus difficile la transition des personnes hors d'un projet. De plus, cela rend tout type d'audit difficile et le suivi des bogues peut être impossible.

Ceci indépendamment du langage utilisé pour la programmation.

D'autres lieux de travail peuvent avoir des coutumes ou des attentes similaires/différentes, voire écrites.

À la maison, vous faites ce que vous voulez.

Par exemple, j'écris des scripts dès que je fais quelque chose non trivial dans le shell, comme avant de soumettre une réponse à une question U&L, ou chaque fois que je dois tester les composants individuels d'une commande ou d'un ensemble des commandes avant de l'exécuter "pour de vrai".

J'écris également des scripts pour des tâches répétitives que je veux vraiment faire de la même manière à chaque fois, même si elles sont simples, comme

  • la mise à jour de mon système OpenBSD et de tous les packages installés (cela revient à trois commandes courtes et une poignée d'autres pour Housekeeping, rassemblées dans un court script), ou
  • sauvegarder mon système sur un stockage hors site (essentiellement une commande nique, mais encore une fois avec beaucoup de ménage et le script me permet également de faire des différences entre les instantanés, etc., et cela doit fonctionner subtilement différent sur différents systèmes, et je l'exécute à partir d'un travail cron), ou
  • récupérer le courrier (encore une fois, essentiellement une seule commande, mais je veux qu'il se comporte différemment lorsqu'il est appelé en tant que tâche cron et lorsque je l'utilise à partir de la ligne de commande, et il ne devrait pas essayer de récupérer le courrier dans certaines circonstances, et il écrit un message de log court dans un fichier).

J'utilise des fonctions Shell (très rarement des alias) pour commodité dans des shells interactifs, par ex. pour ajouter des options à certaines commandes par défaut (-F pour ls) ou pour créer des variations spécialisées de certaines commandes (pman voici une commande man qui ne regarde que les manuels POSIX, par exemple).

5
Kusalananda

Je pense que la plupart du temps, la demande de "one-liner" est en fait une demande de "sound bite", c'est-à-dire:

Dans le contexte du journalisme, une morsure sonore est caractérisée par une courte phrase ou phrase qui capture l'essence de ce que l'orateur essayait de dire, et est utilisée pour résumer les informations ...

Les gens veulent et demandent le code le plus court qui démontre une solution à la question posée.

Parfois, il n'y a aucun moyen de réduire un discours à une "morsure sonore" et il peut être impossible de réduire un script à un court "one-liner". Dans de tels cas, la seule réponse possible est un script.

Et, en général, une "morsure sonore" n'est jamais un bon substitut de tout le discours. Ainsi, un "one liner" n'est généralement bon qu'à transmettre une idée ou à donner un exemple pratique de cette idée. Ensuite, une fois l'idée comprise, elle doit être développée (appliquée) dans un script.

Alors, écrivez un "one-liner" pour transmettre une idée ou un concept.

Écrivez votre code général sous forme de scripts complets et non de lignes simples.

4
Isaac

Vous posez des questions sur "la peur et le dédain des scripts". Cela est dû à la situation Q + A, où souvent la réponse dit: Il a besoin de cette étape et de cela, mais je peux également le mettre sur une seule ligne (afin que vous puissiez copier le coller et l'utiliser comme une simple commande longue).

Vous pouvez parfois seulement deviner si le Q est mieux servi par une solution de copier-coller rapide et sale, ou si un script "Nice" est exactement ce que le Q doit comprendre.

Beaucoup d'avantages et d'inconvénients ici sont vrais, mais il leur manque toujours le point. Je dirais même que les définitions du Q ne sont pas utiles.

Les fichiers Shell history sont des "one liners", mais ils sont toujours enregistrés. La fonction bash operate-and-get-next (C-o) vous permet même de les répéter semi-automatiquement.

Je vois à peine le mot fonction mentionné. C'est la façon de stocker à la fois des "scripts" et des "one liners". Et avec quelques touches, vous pouvez basculer entre les deux formats. Une commande composée peut souvent correspondre aux deux.

history -r file Est le moyen de lire une ou plusieurs lignes de commande (et commentaires) à partir de n'importe quel fichier, pas seulement à partir du fichier historique par défaut. Cela prend juste une organisation minimale. Vous ne devez pas compter sur une grande taille de fichier d'historique et une recherche d'historique pour récupérer (une) version d'une ligne de commande.

Les fonctions doivent être définies de manière similaire. Pour commencer, mettez thisfunc() {...} dans un fichier "fonctions" dans votre répertoire personnel et sourcez-le. Oui, ce sont des frais généraux, mais c'est la solution générale.

Si vous stockez chaque ligne de commande et chaque variante de script dans un fichier séparé, c'est un gaspillage (théorique, mais objectif) de blocs de système de fichiers.

Un doublure n'a rien de rapide et de sale en soi. C'est plus la partie copier-coller qui est un peu désapprouvée, et la façon dont nous nous appuyons simplement sur l'historique des commandes pour l'enregistrer pour nous.


@sitaram: votre doublure a vraiment des fonctionnalités non-unininerish : ligne Shebang, newline, quatre appels d'utilitaire - deux d'entre eux "programmes" sed. Je pense que le script Perl d'origine était plus joli et fonctionnait plus rapidement et n'a pas gaspillé d'octets en s'étalant sur 60 lignes. Et Perl vous permet également de serrer un peu.

Pour moi, c'est exactement le genre de doublure à éviter. Souhaitez-vous avoir cela (collé) sur votre ligne de commande? Non, et si vous le stockez de toute façon dans un fichier (peu importe le script ou la fonction), vous pourriez tout aussi bien investir deux ou trois sauts de ligne pour le faire apparaître --- Nice.


10 minutes. plus tard: je voulais juste vérifier si je peux dire "deux programmes sed" ou si c'est "deux substitutions/appels sed". Mais la réponse de sitaram a disparu. Ma réponse est toujours logique, j'espère.

1
rastafile