Je n'étais pas au courant du prix jusqu'à ce jour où une recrue a essayé de me faire croire que l'UUOC était l'une de mes réponses. C'était un cat file.txt | grep foo | cut ... | cut ...
. Je lui ai donné une partie de mon esprit et ce n’est qu’après cela que j’ai visité le lien qu’il m’avait donné, faisant référence aux origines du prix et à sa pratique. Des recherches plus poussées m'ont amené à cette question. Malheureusement, malgré une réflexion consciente, aucune des réponses n’a inclus ma justification.
Je ne voulais pas être sur la défensive quand je l'éduquais. Après tout, dans ma jeunesse, j’aurais écrit la commande grep foo file.txt | cut ... | cut ...
car, chaque fois que vous exécutez les célibataires fréquents, grep
vous apprenez le placement de l’argument du fichier. Vous savez donc que le premier est le motif et que les derniers sont des noms de fichiers.
C'était un choix conscient lorsque j'ai répondu à la question avec le cat
préfixe en partie pour une raison de "bon goût" (selon les mots de Linus Torvalds), mais principalement pour une raison impérieuse de fonction.
La dernière raison est plus importante, je vais donc la publier en premier. Lorsque j'offre un pipeline comme solution, je m'attends à ce qu'il soit réutilisable. Il est fort probable qu'un pipeline soit ajouté à la fin ou raccordé à un autre pipeline. Dans ce cas, avoir un argument de fichier à grep réduit les possibilités de réutilisation, et le fait probablement de manière silencieuse sans message d'erreur si l'argument de fichier existe. C'est à dire. grep foo xyz | grep bar xyz | wc
vous donnera le nombre de lignes xyz
contenues bar
pendant que vous attendez le nombre de lignes contenant à la fois foo
et bar
. Devoir changer les arguments d'une commande dans un pipeline avant de l'utiliser est sujet aux erreurs. Ajoutez à cela la possibilité d'échecs silencieux et cela devient une pratique particulièrement insidieuse.
La première raison n’est pas sans importance non plus, car beaucoup de "bon goût" est simplement une logique subconsciente intuitive pour des choses comme les échecs silencieux ci-dessus que vous ne pouvez pas imaginer juste au moment où une personne ayant besoin d’éducation dit "mais ne le fait pas". ce chat inutile ".
Cependant, je vais essayer de rendre également conscient la raison "bon goût" que j'ai mentionnée. Cette raison est liée à l'esprit de conception orthogonale d'Unix. grep
ne fait pas cut
et ls
ne fait pas grep
. Par conséquent, à tout le moins grep foo file1 file2 file3
va à l’encontre de l’esprit de conception. La façon orthogonale de le faire est cat file1 file2 file3 | grep foo
. Maintenant, il grep foo file1
s’agit simplement d’un cas particulier de grep foo file1 file2 file3
, et si vous ne le traitez pas de la même façon, vous utilisez au moins des cycles d’horloge cérébrale en essayant d’éviter l’attribution inutile du chat.
Cela nous amène à l’argument qui grep foo file1 file2 file3
concatène, et cat
concatène donc comme il convient cat file1 file2 file3
mais parce que cat
ne concaténant pas, nous violons cat file1 | grep foo
donc l’esprit de cat
l’Unix et du tout-puissant. Eh bien, si c'était le cas, Unix aurait besoin d'une commande différente pour lire la sortie d'un fichier et le cracher sur stdout (pas le paginer ni quoi que ce soit d'autre qu'un simple crachage sur stdout). Ainsi, vous auriez la situation où vous dites cat file1 file2
ou que vous dites dog file1
et souvenez-vous consciencieusement d’éviter cat file1
d’obtenir le prix, tout en évitant dog file1 file2
puisque espérons-le, la conception de dog
jetterait une erreur si plusieurs fichiers sont spécifiés.
J'espère qu'à ce stade, vous sympathisez avec les concepteurs Unix pour ne pas inclure de commande distincte pour cracher un fichier sur stdout, tout en nommant cat
pour concaténer plutôt que de lui attribuer un autre nom. <edit>
il y a un tel chien, l' <
opérateur malheureux . Il est regrettable que son placement à la fin du pipeline empêche toute possibilité de composition. Il n’existe aucun moyen propre, au niveau syntaxique ou esthétique, de le placer au début. Il est également regrettable de ne pas être assez généraliste, vous devez donc commencer par le chien, mais simplement ajouter un autre nom de fichier si vous souhaitez également le traiter après le précédent. (En >
revanche, ce n'est pas aussi grave. Son placement est presque parfait à la fin. Il ne s'agit généralement pas d'une partie réutilisable d'un pipeline et il est donc distingué de manière symbolique.)</edit>
La question suivante est pourquoi est-il important d’avoir des commandes qui crachent un fichier ou la concaténation de plusieurs fichiers sur stdout, sans autre traitement? Une des raisons est d'éviter d'avoir chaque commande Unix qui fonctionne sur une entrée standard pour savoir comment analyser au moins un argument de fichier de ligne de commande et l'utiliser comme entrée s'il existe. La deuxième raison est d'éviter que les utilisateurs aient à se rappeler: (a) où vont les arguments de nom de fichier; et (b) éviter le bogue du pipeline silencieux mentionné ci-dessus.
Cela nous amène à pourquoi grep
a la logique supplémentaire. L'objectif est de permettre aux utilisateurs d'utiliser couramment des commandes fréquemment et de manière autonome (plutôt que sous forme de pipeline). C'est un léger compromis d'orthogonalité pour un gain de convivialité significatif. Toutes les commandes ne doivent pas nécessairement être conçues de cette façon et les commandes peu 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 consiste à autoriser les arguments de fichier comme dans le cas de grep
. (Au fait, notez que la ls
raison qui sous-tend une argumentation complètement différente est non seulement d’accepter mais également d’exiger des arguments de fichier)
Enfin, on aurait pu mieux faire si des commandes exceptionnelles telles que grep
(mais pas nécessairement ls
) généraient une erreur si l'entrée standard était disponible. Ceci est raisonnable car les commandes incluent une logique qui viole l’esprit orthogonal du tout-puissant Unix pour plus de commodité. Pour plus de commodité, c'est-à-dire pour éviter les souffrances causées par une défaillance silencieuse, ces commandes ne doivent pas hésiter à violer leur propre violation en avertissant l'utilisateur de la possibilité d'une défaillance silencieuse.