Я не знал о награде до сегодняшнего дня, когда какой-то новобранец пытался прикрепить UUOC на меня для одного из моих ответов. Это был cat file.txt | grep foo | cut ... | cut ...
Я дал ему часть своего разума, и только после этого посетил ссылку, которую он дал мне, ссылаясь на происхождение награды и практику этого. Дальнейшие поиски привели меня к этому вопросу. К сожалению, несмотря на сознательное рассмотрение, ни один из ответов не содержал моего обоснования.
Я не хотел защищаться, обучая его. В конце концов, в молодости я написал бы команду как grep foo file.txt | cut ... | cut ...
потому что всякий раз, когда вы выполняете частые одиночные grep
вы изучаете размещение аргумента файла, и вы уже знаете, что первым является шаблон, а последующими - имена файлов.
Это был осознанный выбор, когда я ответил на вопрос с префиксом « cat
частично из-за причины "хорошего вкуса" (по словам Линуса Торвальдса), но главным образом из-за убедительной причины функционирования.
Последняя причина более важна, поэтому я изложу ее в первую очередь. Когда я предлагаю трубопровод в качестве решения, я ожидаю, что его можно будет использовать повторно. Вполне вероятно, что конвейер будет добавлен в конце или объединен в другой конвейер. В этом случае имея файл аргумент Grep винты до повторного, и вполне возможно , сделать это тихо и без сообщения об ошибке , если файл существует аргумент. И. е. grep foo xyz | grep bar xyz | wc
, сколько строк в xyz
содержит bar
а вы ожидаете количество строк, которые содержат как foo
и bar
. Необходимость изменить аргументы команды в конвейере перед ее использованием подвержена ошибкам. Добавьте к этому возможность молчаливых неудач, и это становится особенно коварной практикой.
Не менее важна и первая причина, так как много "хорошего вкуса" просто является интуитивным подсознательным обоснованием таких вещей, как молчаливые неудачи, описанные выше, о которых вы не можете вспомнить прямо в тот момент, когда какой-то человек, нуждающийся в образовании, говорит «но не этот кот бесполезен ".
Тем не менее, я постараюсь также осознать прежнюю причину "хорошего вкуса", которую я упомянул. Эта причина связана с ортогональным духом дизайна Unix. grep
не cut
и ls
не grep
. Поэтому, по крайней мере, grep foo file1 file2 file3
идет вразрез с духом дизайна. Ортогональный способ сделать это - cat file1 file2 file3 | grep foo
Теперь, grep foo file1
- это просто особый случай grep foo file1 file2 file3
, и если вы не относитесь к нему одинаково, вы, по крайней мере, используете мозговые циклы, пытаясь избежать бесполезного вознаграждения кошек.
Это приводит нас к аргументу о том, что grep foo file1 file2 file3
объединяется, а cat
объединяется, поэтому он подходит для cat file1 file2 file3
а потому что cat
не объединяет в cat file1 | grep foo
поэтому мы нарушаем дух и cat
и всемогущего Unix. Что ж, если бы это было так, тогда Unix потребовалась бы другая команда, чтобы прочитать вывод одного файла и выложить его на стандартный вывод (не разбивать его на страницы или что-то еще, просто наплевать на стандартный вывод). Таким образом, у вас может возникнуть ситуация, когда вы говорите « cat file1 file2
или « dog file1
и добросовестно не забываете избегать « cat file1
чтобы избежать получения награды, и в то же время избегать « dog file1 file2
так как, надеюсь, дизайн « dog
выдаст ошибку, если несколько файлов будут указано.
Надеемся, что в этот момент вы сочувствуете разработчикам Unix за то, что вы не включили отдельную команду для разбивки файла на стандартный вывод, а также назвали cat
для сцепления вместо того, чтобы давать ему другое имя. <edit>
есть такая собака, несчастный <
оператор. К сожалению, его размещение в конце трубопровода препятствует легкому составлению. Нет синтаксически или эстетически чистого способа разместить его в начале. К сожалению, недостаточно универсален, поэтому вы начинаете с собаки, а просто добавляете другое имя файла, если хотите, чтобы оно обрабатывалось после предыдущего. >
с другой стороны , это не половина так плохо. У него почти идеальное расположение в конце. Как правило, это не многократно используемая часть конвейера, и, соответственно, он различается символически.)</edit>
Следующий вопрос: почему так важно иметь команды, которые просто выплевывают файл или объединяют несколько файлов в стандартный вывод без какой-либо дальнейшей обработки? Одна из причин - избегать использования каждой отдельной команды Unix, работающей со стандартным вводом, чтобы знать, как анализировать хотя бы один аргумент файла командной строки и использовать его в качестве ввода, если он существует. Вторая причина заключается в том, чтобы пользователям не приходилось запоминать: (а) куда идут аргументы имени файла; и (b) избежать ошибки тихого конвейера, как упомянуто выше.
Это подводит нас к тому, почему у grep
есть дополнительная логика. Обоснование заключается в том, чтобы обеспечить свободное владение пользователями для команд, которые используются часто и в автономном режиме (а не в качестве конвейера). Это небольшой компромисс ортогональности для значительного увеличения удобства использования. Не все команды должны быть спроектированы таким образом, и команды, которые не используются часто, должны полностью избегать дополнительной логики аргументов файла (помните, что дополнительная логика приводит к ненужной хрупкости (возможность ошибки)). Исключением является разрешение файловых аргументов, как в случае с grep
. (кстати, обратите внимание, что ls
имеет совершенно другую причину, чтобы не просто принимать, а в значительной степени требовать аргументы файла)
Наконец, то, что можно было бы сделать лучше, это если такие исключительные команды, как grep
(но не обязательно ls
), генерируют ошибку, если доступен стандартный ввод. Это разумно, потому что команды включают логику, которая нарушает ортогональный дух всемогущего Unix для удобства пользователя. Для дальнейшего удобства пользователя, т.е. для предотвращения страданий, вызванных молчаливым отказом, такие команды не должны стесняться нарушать собственное нарушение, предупреждая пользователя, если существует возможность молчаливого отказа.