45 votes

Quel est le consensus général sur "l'utilisation inutile d'un chat" ?

Lorsque j'envoie plusieurs commandes unix telles que grep, sed, tr, etc. j'ai tendance à spécifier le fichier d'entrée qui est traité par cat. Ainsi, quelque chose comme cat file | grep ... | awk ... | sed ... .

Mais récemment, après avoir reçu quelques commentaires sur mes réponses indiquant qu'il s'agissait d'une utilisation inutile du chat, j'ai pensé poser la question ici.

Je me suis renseigné sur la question et je suis tombé sur Article de Wikipédia sur l'UUOC y L'utilisation inutile du prix du chat et il me semble que les arguments avancés s'inscrivent dans une perspective d'efficacité.

La question la plus proche que j'ai rencontrée est celle-ci : Est-ce un gaspillage que d'appeler un chat ? - mais ce n'est pas tout à fait ce que je demande.

Je suppose que le camp de l'UUOC suggère d'utiliser cmd1 args < file | cmd2 args | cmd3 .. ou, si la commande comporte une option de lecture à partir d'un fichier, de transmettre le fichier en tant qu'argument.

Mais pour moi cat file | cmd1 ... | cmd2 semble beaucoup plus facile à lire et à comprendre. Je n'ai pas à me souvenir des différentes manières d'envoyer les fichiers d'entrée aux différentes commandes, et le processus se déroule logiquement de gauche à droite. D'abord l'entrée, puis le premier processus ... et ainsi de suite.

Est-ce que je ne comprends pas les arguments avancés pour justifier l'utilisation inutile du chat ? Je comprends que si je lance une tâche cron qui s'exécute toutes les 2 secondes et qui fait beaucoup de traitement, alors dans ce cas cat peut être un gaspillage. Mais sinon, quel est le consensus général sur l'utilisation de cat ?

24voto

Daniel Beck Points 105590

Il est inutile dans le sens où l'utiliser de la sorte ne permet pas d'accomplir ce que les autres options, éventuellement plus efficaces, ne peuvent pas faire (c'est-à-dire produire des résultats corrects).

Pero cat est bien plus puissant que le simple cat somefile . Consulter man cat ou lire ce que j'ai écrit dans cette réponse . Mais si vous n'avez absolument besoin que du contenu d'un seul fichier, vous pourriez bénéficier d'un certain avantage en termes de performances en n'utilisant pas la fonction cat pour accéder au contenu du fichier.

En ce qui concerne la lisibilité, cela dépend de vos goûts personnels. J'aime cat Il n'est pas possible d'intégrer des fichiers dans d'autres commandes pour la même raison, surtout si les aspects liés à la performance sont négligeables.

Cela dépend également de ce que vous écrivez. S'il s'agit de votre propre Shell et de méthodes de commodité pour votre machine de bureau, personne d'autre que vous ne s'en souciera. Si vous tombez sur un cas où l'outil suivant dans la chaîne serait mieux de pouvoir chercher, et distribuer cela comme un logiciel fréquemment utilisé sur un système Linux minimal sur un routeur de faible performance ou un appareil similaire avec des limites réelles sur la capacité de traitement, c'est différent. Cela dépend toujours du contexte.

23voto

Ole Tange Points 4059

J'utilise souvent cat file | myprogram dans les exemples. On m'accuse parfois d'utiliser inutilement le mot "chat" ( http://www.iki.fi/era/unix/award.html ). Je ne suis pas d'accord pour les raisons suivantes :

Il est facile de comprendre ce qui se passe.

Lorsque vous lisez une commande UNIX, vous vous attendez à une commande suivie de d'arguments suivis d'une redirection. Il n'en est rien. es Il est possible de mettre le redirection n'importe où mais elle est rarement vue - les gens auront donc du mal à s'y retrouver. plus de mal à lire l'exemple. Je crois que

    cat foo | program1 -o option -b option | program2

est plus facile à lire que

    program1 -o option -b option < foo | program2

Si vous déplacez la redirection vers au début, vous risquez d'embrouiller les personnes qui ne sont pas habituées à cette syntaxe :

    < foo program1 -o option -b option | program2

et les exemples devraient doivent être faciles à comprendre.

Il est facile à modifier.

Si vous savez que le programme peut lire à partir de cat, vous pouvez normalement supposer qu'il peut lire la sortie de n'importe quel programme qui sort sur STDOUT, et vous pouvez donc l'adapter à vos propres besoins et obtenir des résultats prévisibles.

Il souligne que le programme n'échoue pas si STDIN n'est pas un fichier normal.

Il n'est pas sûr que si program1 < foo fonctionne alors cat foo | program1 fonctionnera également. Cependant, il es en pratique, on peut supposer que c'est le contraire. Ce programme fonctionne si STDIN est un fichier, mais échoue si l'entrée est un tuyau, car il utilise la recherche :

    # works
    < foo perl -e 'seek(STDIN,1,1) || die;print <STDIN>'

    # fails
    cat foo | perl -e 'seek(STDIN,1,1) || die;print <STDIN>'

La pénalité de performance n'est souvent pas mesurable.

J'ai examiné la pénalité de performance sur http://oletange.blogspot.dk/2013/10/useless-use-of-cat.html La conclusion est qu'il ne faut pas utiliser cat file | si la complexité du traitement est similaire à un simple grep et que la performance importe plus que la lisibilité. Dans d'autres cas cat file | est très bien.

Voici un exemple où | cat aumenta de 50 % : https://unix.stackexchange.com/questions/614154/useless-use-of-cat-increases-performance-why

17voto

bahamat Points 5456

Dans l'utilisation quotidienne de la ligne de commande, ce n'est pas très différent. Vous ne remarquerez surtout pas de différence de vitesse puisque le temps passé sur le processeur en n'utilisant pas la fonction cat votre processeur va rester inactif. Même si vous parcourez en boucle des centaines ou des milliers (voire des centaines de milliers) d'éléments, dans la pratique, cela ne va pas faire de l'argent. beaucoup à moins que vous ne soyez sur un système très chargé (Load Average / N CPU > 1).

Le point de rencontre entre le caoutchouc et la route consiste à former de bonnes habitudes et à décourager les mauvaises. Pour reprendre un vieux cliché, le diable se cache dans les détails. Et ce sont des détails comme celui-ci qui séparent le médiocre de l'excellent.

C'est comme lorsqu'on conduit une voiture : pourquoi tourner à gauche quand on peut tourner à droite ? Bien sûr, vous pouvez le faire et cela fonctionne parfaitement. Mais si vous avez compris l'importance des virages à gauche, les trois virages à droite vous paraissent tout simplement stupides.

Il ne s'agit pas d'économiser un gestionnaire de fichier, 17k de RAM et 0,004 seconde de temps CPU. Il s'agit de toute la philosophie d'utilisation d'UNIX. Le "pouvoir des virages à gauche" de mon illustration n'est pas simplement la redirection des entrées, c'est la philosophie d'UNIX. En la comprenant parfaitement, vous excellerez bien mieux que ceux qui vous entourent et vous gagnerez le respect de ceux qui la comprennent.

13voto

Unnati Gutpa Points 11

Je pense que la position adoptée par certains de ceux qui commentent quelque chose comme étant un UUOC est que si l'on comprend vraiment Unix et la syntaxe Shell, on n'utiliserait pas cat dans ce contexte. C'est comme une mauvaise grammaire : je peux écrire une phrase en utilisant une mauvaise grammaire et faire passer mon message, mais je démontre également ma mauvaise compréhension de la langue et, par extension, mon manque d'éducation. Ainsi, dire que quelque chose est un UUOC est une autre façon de dire que quelqu'un ne comprend pas ce qu'il fait.

En ce qui concerne l'efficacité, si vous exécutez un pipeline à partir de la ligne de commande, il faut moins de temps à la machine pour l'exécuter. cat somefile | que de réfléchir à la question de savoir s'il ne serait pas plus efficace d'utiliser le système d'information sur la santé. < somefile . Cela n'a pas d'importance.

5voto

randomstring Points 186

Je n'étais pas au courant de cette récompense jusqu'à aujourd'hui, lorsqu'un débutant a essayé de me coller l'UUOC sur le dos pour l'une de mes réponses. Il s'agissait d'une cat file.txt | grep foo | cut ... | cut ... . Je lui ai fait part de mes réflexions et ce n'est qu'après avoir consulté le lien qu'il m'a donné concernant les origines du prix et la pratique en la matière. Une recherche plus approfondie m'a conduit à cette question. Malheureusement, en dépit d'une réflexion approfondie, aucune des réponses n'incluait mon raisonnement.

Je n'avais pas l'intention d'être sur la défensive en l'éduquant. Après tout, dans mes jeunes années, j'aurais écrit la commande comme suit grep foo file.txt | cut ... | cut ... parce qu'à chaque fois que l'on fait le single fréquent grep vous apprenez l'emplacement de l'argument du fichier et vous savez déjà que le premier est le modèle et que les suivants sont des noms de fichiers.

C'est en toute connaissance de cause que j'ai répondu à la question par la formule cat préfixe en partie pour une raison de "bon goût" (selon les termes de Linus Torvalds), mais surtout pour une raison impérieuse de fonction.

Cette dernière raison étant plus importante, je l'exposerai en premier. Lorsque je propose un pipeline comme solution, je m'attends à ce qu'il soit réutilisable. Il est tout à fait probable qu'un pipeline soit ajouté à la fin d'un autre pipeline ou qu'il s'y greffe. Dans ce cas, le fait d'avoir un argument fichier pour grep gêne la réutilisation, et peut très bien le faire en silence sans message d'erreur si l'argument fichier existe. I. e. grep foo xyz | grep bar xyz | wc vous donnera le nombre de lignes dans xyz contenir bar alors que vous attendez le nombre de lignes qui contiennent à la fois foo y bar . Le fait de devoir modifier les arguments d'une commande dans un pipeline avant de l'utiliser est source d'erreurs. Si l'on ajoute à cela la possibilité d'échecs silencieux, cette pratique devient particulièrement insidieuse.

La première raison n'est pas sans importance non plus, car une grande partie du "bon goût" n'est qu'une justification intuitive et subconsciente de choses telles que les échecs silencieux mentionnés ci-dessus, auxquels vous ne pouvez pas penser au moment où une personne ayant besoin d'éducation dit "mais ce chat n'est pas inutile".

Cependant, j'essaierai de rendre consciente la raison de "bon goût" que j'ai mentionnée précédemment. Cette raison est liée à l'esprit de conception orthogonale d'Unix. grep n'est pas cut y ls n'est pas grep . Par conséquent, au minimum grep foo file1 file2 file3 va à l'encontre de l'esprit du design. La manière orthogonale de procéder est la suivante cat file1 file2 file3 | grep foo . Maintenant, grep foo file1 est simplement un cas particulier de grep foo file1 file2 file3 Si vous ne le traitez pas de la même manière, vous utilisez au moins des cycles d'horloge cérébrale en essayant d'éviter le prix du chat inutile.

Cela nous amène à l'argument selon lequel grep foo file1 file2 file3 est une concaténation, et cat concatène, il convient donc de cat file1 file2 file3 mais parce que cat n'est pas concaténée dans cat file1 | grep foo Par conséquent, nous violons l'esprit de l'accord de l'Union européenne. cat et le tout puissant Unix. Si c'était le cas, Unix aurait besoin d'une commande différente pour lire la sortie d'un fichier et la recracher sur stdout (sans la paginer ou quoi que ce soit d'autre, mais en la recrachant purement sur stdout). On se retrouverait donc dans la situation où l'on dirait cat file1 file2 ou vous dites dog file1 et se rappeler consciencieusement d'éviter cat file1 pour éviter de recevoir la récompense, tout en évitant dog file1 file2 puisqu'il faut espérer que la conception de dog génère une erreur si plusieurs fichiers sont spécifiés.

J'espère qu'à ce stade, vous comprenez que les concepteurs d'Unix n'ont pas inclus de commande distincte pour cracher un fichier sur stdout, et qu'ils ont nommé cat pour concaténer plutôt que de lui donner un autre nom. <edit> il existe un tel chien, le malheureux < de l'opérateur. Il est regrettable qu'il soit placé à la fin du pipeline, ce qui l'empêche d'être facilement composable. Il n'y a pas de moyen syntaxique ou esthétique de le placer au début. Il est également regrettable qu'il ne soit pas assez général pour que vous commenciez avec le chien, mais que vous puissiez simplement ajouter un autre nom de fichier si vous souhaitez qu'il soit traité après le précédent. (Le > n'est pas aussi mauvais. Il est presque parfaitement placé à la fin. Il ne s'agit généralement pas d'une partie réutilisable d'un pipeline, et c'est pourquoi il est distingué symboliquement). </edit>

La question suivante est de savoir pourquoi il est important d'avoir des commandes qui crachent simplement un fichier ou la concaténation de plusieurs fichiers sur stdout, sans aucun autre traitement ? L'une des raisons est d'éviter que chaque commande Unix opérant sur l'entrée standard sache comment analyser au moins un argument de fichier de la ligne de commande et l'utiliser comme entrée s'il existe. La seconde raison est d'éviter que les utilisateurs aient à se rappeler : (a) où vont les arguments de nom de fichier ; et (b) d'éviter le bogue du pipeline silencieux mentionné ci-dessus.

Cela nous amène à la question de savoir pourquoi grep dispose d'une logique supplémentaire. L'objectif est de permettre à l'utilisateur de faire preuve de fluidité dans l'utilisation des commandes qui sont utilisées fréquemment et sur une grande échelle. autonome (plutôt que comme un pipeline). Il s'agit d'un léger compromis d'orthogonalité pour un gain significatif de convivialité. Toutes les commandes ne doivent pas être conçues de cette manière et les commandes qui ne sont pas fréquemment utilisées doivent éviter complètement la logique supplémentaire des arguments de fichier (rappelez-vous que la logique supplémentaire entraîne une fragilité inutile (la possibilité d'un bogue)). L'exception est d'autoriser les arguments de fichier comme dans le cas de grep . (à ce propos, notez que ls a une raison complètement différente de ne pas seulement accepter, mais plutôt d'exiger des arguments de fichier)

Enfin, ce qui aurait pu être mieux fait, c'est que des commandes exceptionnelles telles que grep (mais pas nécessairement ls ) génère une erreur si l'entrée standard est disponible. Ceci est raisonnable car les commandes incluent une logique qui viole l'esprit orthogonal du tout-puissant Unix pour le confort de l'utilisateur. Pour plus de commodité, c'est-à-dire pour éviter les souffrances causées par un échec silencieux, ces commandes ne devraient pas hésiter à violer leur propre violation en alertant l'utilisateur s'il y a une possibilité d'échec silencieux.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X