No estaba al tanto del premio hasta hoy, cuando un novato intentó ponerme el UUOC por una de mis respuestas. Fue a cat file.txt | grep foo | cut ... | cut ...
. Le di una parte de mi mente, y solo después de hacerlo visité el enlace que me dio refiriéndome a los orígenes del premio y la práctica de hacerlo. Una búsqueda más profunda me llevó a esta pregunta. Desafortunadamente, a pesar de la consideración consciente, ninguna de las respuestas incluyó mi justificación.
No quise ponerme a la defensiva cuando lo educaba. Después de todo, en mis años más jóvenes habría escrito el comando como grep foo file.txt | cut ... | cut ...
porque cada vez que haces los solteros frecuentes grep
aprendes la ubicación del argumento del archivo y es fácil saber que el primero es el patrón y los posteriores son los nombres de los archivos.
Fue una elección consciente cuando respondí la pregunta con el cat
prefijo en parte debido a una razón de "buen gusto" (en palabras de Linus Torvalds), pero principalmente por una razón de función convincente.
La última razón es más importante, así que lo expondré primero. Cuando ofrezco una tubería como solución, espero que sea reutilizable. Es muy probable que una tubería se agregue al final o se empalme en otra tubería. En ese caso, tener un argumento de archivo para grep arruina la reutilización, y muy posiblemente lo haga en silencio sin un mensaje de error si el argumento del archivo existe. I. e. grep foo xyz | grep bar xyz | wc
le dará cuántas líneas xyz
contiene bar
mientras espera el número de líneas que contienen ambos foo
y bar
. Tener que cambiar los argumentos a un comando en una tubería antes de usarlo es propenso a errores. Agregue a esto la posibilidad de fallas silenciosas y se convierte en una práctica particularmente insidiosa.
La razón anterior tampoco es importante ya que una gran cantidad de "buen gusto" es simplemente una razón subconsciente intuitiva para cosas como las fallas silenciosas anteriores que no se puede pensar en el momento en que una persona necesitada de educación dice "pero no ese gato inútil ".
Sin embargo, trataré de hacer consciente también la razón anterior del "buen gusto" que mencioné. Esa razón tiene que ver con el espíritu de diseño ortogonal de Unix. grep
no lo hace cut
y ls
no lo hace grep
. Por lo tanto, al menos grep foo file1 file2 file3
va en contra del espíritu de diseño. La forma ortogonal de hacerlo es cat file1 file2 file3 | grep foo
. Ahora, grep foo file1
es simplemente un caso especial de grep foo file1 file2 file3
, y si no lo trata de la misma manera, al menos está agotando los ciclos del reloj cerebral tratando de evitar el premio inútil del gato.
Eso nos lleva al argumento de que grep foo file1 file2 file3
es concatenante, y se cat
concatena, por lo que es apropiado, cat file1 file2 file3
pero porque cat
no es concatenante, cat file1 | grep foo
por lo tanto, estamos violando el espíritu de cat
Unix y del todopoderoso. Bueno, si ese fuera el caso, entonces Unix necesitaría un comando diferente para leer la salida de un archivo y escupirlo en stdout (no paginarlo ni nada simplemente un spit para stdout). Por lo tanto, tendría la situación en la que dice cat file1 file2
o dice dog file1
y recuerda concienzudamente evitar cat file1
evitar obtener el premio, al tiempo que evita dog file1 file2
que, con suerte, el diseño dog
arroje un error si se especifican varios archivos.
Afortunadamente, en este punto, simpatiza con los diseñadores de Unix por no incluir un comando separado para escupir un archivo a stdout, mientras que también nombra cat
para concatenar en lugar de darle otro nombre. <edit>
hay un perro así, el desafortunado <
operador. Es desafortunado su ubicación al final de la tubería, lo que impide su fácil componibilidad. No hay una forma sintáctica o estéticamente limpia de colocarlo al principio. También es desafortunado no ser lo suficientemente general, por lo que comienza con el perro pero simplemente agrega otro nombre de archivo si también desea que se procese después del anterior. (Por >
otro lado, no es la mitad de malo. Tiene una ubicación casi perfecta al final. Por lo general, no es una parte reutilizable de una tubería, y en consecuencia se distingue simbólicamente).</edit>
La siguiente pregunta es ¿por qué es importante tener comandos que simplemente escupen un archivo o la concatenación de varios archivos a stdout, sin ningún procesamiento adicional? Una razón es evitar tener todos los comandos de Unix que operan en la entrada estándar para saber cómo analizar al menos un argumento de archivo de línea de comando y usarlo como entrada si existe. La segunda razón es evitar que los usuarios tengan que recordar: (a) dónde van los argumentos del nombre de archivo; y (b) evite el error silencioso de la tubería como se mencionó anteriormente.
Eso nos lleva a por qué grep
tiene la lógica extra. La razón es permitir la fluidez del usuario para los comandos que se usan con frecuencia y de forma independiente (en lugar de como una tubería). Es un ligero compromiso de ortogonalidad para una ganancia significativa en la usabilidad. No todos los comandos deben diseñarse de esta manera y los comandos que no se usan con frecuencia deben evitar por completo la lógica adicional de los argumentos del archivo (recuerde que la lógica adicional conduce a una fragilidad innecesaria (la posibilidad de un error)). La excepción es permitir argumentos de archivo como en el caso de grep
. (por cierto, tenga en cuenta que ls
tiene una razón completamente diferente para no solo aceptar, sino que también requiere argumentos de archivo)
Finalmente, lo que podría haberse hecho mejor es si comandos tan excepcionales como grep
(pero no necesariamente ls
) generan un error si la entrada estándar está disponible. Esto es razonable porque los comandos incluyen lógica que viola el espíritu ortogonal del todopoderoso Unix para comodidad del usuario. Para mayor comodidad del usuario, es decir, para evitar el sufrimiento causado por una falla silenciosa, tales comandos no deben dudar en violar su propia violación al alertar al usuario si existe la posibilidad de una falla silenciosa.