Вероятно, это есть во многих часто задаваемых вопросах - вместо использования:
cat file | command
(что называется бесполезным использованием кошки), правильный путь должен быть таким:
command < file
Во втором, «правильном» варианте - ОС не должна порождать лишний процесс.
Несмотря на это, я продолжал использовать бесполезную кошку по двум причинам.
более эстетичный - мне нравится, когда данные перемещаются равномерно только слева направо. И это легче заменить
cat
чем - то другим (gzcat
,echo
, ...), добавьте 2 - й файл или вставить новый фильтр (pv
,mbuffer
,grep
...).Я «почувствовал», что в некоторых случаях это может быть быстрее. Быстрее, потому что есть 2 процесса: 1-й (
cat
) выполняет чтение, а второй - что угодно. И они могут работать параллельно, что иногда означает более быстрое выполнение.
Моя логика верна (по 2-й причине)?
источник
cat
это трубка идентичности . Он только передает свой ввод на свой вывод. Если вторая программа в цепочке может принимать входные данные из того же аргумента, которому вы передаетеcat
(или из стандартного ввода, если вы не передаете аргумент), тоcat
она абсолютно бесполезна и приводит только к разветвлению дополнительного процесса и созданию дополнительной трубы. создан.-
, это канал идентификации. Когда он имеет более одного аргумента имени файла без тире, он становится чем-то большим, чем канал идентификации, и начинает служить реальной цели.<file command1 | command2
, хотя возникнут разногласия по поводу эстетики.Ответы:
Я не знал о награде до сегодняшнего дня, когда какой-то новичок попытался повесить на меня UUOC за один из моих ответов. Это был
cat file.txt | grep foo | cut ... | cut ...
. Я поделился с ним своим мнением и только после этого перешел по ссылке, которую он дал мне, касаясь происхождения награды и практики ее получения. Дальнейшие поиски привели меня к этому вопросу. К сожалению, несмотря на сознательное рассмотрение, ни один из ответов не содержал моего обоснования.Я не собирался защищаться, отвечая ему. В конце концов, в мои молодые годы я бы написал команду так,
grep foo file.txt | cut ... | cut ...
потому что всякий раз, когда вы выполняете частые синглы,grep
вы изучаете размещение аргумента файла, и уже заранее известно, что первый - это шаблон, а последующие - имена файлов.cat
Когда я ответил на вопрос, это был осознанный выбор , отчасти по причине «хорошего вкуса» (по словам Линуса Торвальдса), но в основном по веской причине функциональности.Последняя причина более важна, поэтому я расскажу об этом первым. Когда я предлагаю в качестве решения конвейер, я ожидаю, что его можно будет использовать повторно. Вполне вероятно, что конвейер будет добавлен в конце или соединен с другим конвейером. В этом случае файл , имеющий аргумент Grep щурит многократное использование, и вполне возможно , сделать это тихо и без сообщения об ошибке , если файл существует аргумент. I. e.
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. Что ж, если бы это было так, тогда Unix потребовалась бы другая команда для чтения вывода одного файла и вывода его на stdout (не разбивать его на страницы или что-то просто чистое слюнение на stdout). Таким образом, у вас может возникнуть ситуация, когда вы говоритеcat file1 file2
или говоритеdog file1
и сознательно помните, чтобы избежатьcat file1
получения награды, а также избегайте,dog file1 file2
поскольку, надеюсь, конструкцияdog
выдаст ошибку, если указано несколько файлов.Надеюсь, на этом этапе вы сочувствуете разработчикам Unix за то, что они не включили отдельную команду для вывода файла на стандартный вывод, а также
cat
дали имя для конкатенации, а не дали ему другое имя.<edit>
на<
самом деле удаленные неправильные комментарии<
- это эффективное средство без копирования для вывода файла на стандартный вывод, который можно разместить в начале конвейера, поэтому разработчики Unix включили что-то специально для этого</edit>
Следующий вопрос: почему важно иметь команды, которые просто выводят файл или объединяют несколько файлов в стандартный вывод без какой-либо дальнейшей обработки? Одна из причин - избегать того, чтобы каждая команда Unix, которая работает со стандартным вводом, знала, как анализировать хотя бы один аргумент файла командной строки и использовать его в качестве ввода, если он существует. Вторая причина состоит в том, чтобы пользователи не запоминали: (а) куда идут аргументы имени файла; и (b) избежать ошибки молчащего конвейера, как упомянуто выше.
Это подводит нас к тому, почему
grep
есть лишняя логика. Обоснование состоит в том, чтобы позволить пользователю свободно использовать команды, которые используются часто и автономно (а не как конвейер). Это небольшой компромисс ортогональности для значительного увеличения удобства использования. Не все команды следует разрабатывать таким образом, и команды, которые не часто используются, должны полностью избегать дополнительной логики аргументов файла (помните, что дополнительная логика ведет к ненужной хрупкости (возможности ошибки)). Исключением является разрешение аргументов файла, как в случаеgrep
. (Кстати, обратите внимание, чтоls
есть совершенно другая причина не просто принимать, но в значительной степени требовать аргументы файла)Наконец, можно было бы сделать лучше, если бы такие исключительные команды, как
grep
(но не обязательноls
) генерировали ошибку, если стандартный ввод также доступен, когда указаны аргументы файла.источник
grep
вызове с несколькими именами файлов он добавляет к найденным строкам префикс имени файла, в котором он был найден (если вы не отключите это поведение). Он также может сообщать номера строк в отдельных файлах. Если использовать толькоcat
для подачиgrep
, вы потеряете имена файлов, и номера строк будут непрерывными для всех файлов, а не для каждого файла. Таким образом, есть причины, по которым приходитсяgrep
обрабатывать несколько файлов самостоятельноcat
. Случаи с одним файлом и с нулевым файлом - это просто частные случаи общего использования нескольких файловgrep
.< file command1 ...
. Хотя обычно операторы перенаправления ввода-вывода располагаются после имени команды и ее аргументов, это всего лишь соглашение, а не обязательное размещение. Имя<
должно предшествовать имени файла. Таким образом, есть близко к идеальной симметрии между>output
и<input
перенаправлениям:<input command1 -opt 1 | command2 -o | command3 >output
.cat
это бесполезно. Это неcat
бесполезно; дело в том, что конкретная конструкция не нуждается в использованииcat
. Если хотите, обратите внимание, что это UUoC (бесполезное использованиеcat
), а не UoUC (использование бесполезногоcat
). Есть много случаев, когдаcat
это правильный инструмент; У меня нет проблем с его использованием, когда это правильный инструмент (и, действительно, упомянул случай в моем ответе).cat
в конвейере может не иметь большого значения в зависимости от данных, но при использовании в качестве среды программирования может быть абсолютно необходимо реализовать эти важные для производительности вещи; особенно когда имеешь дело сbash
колесом прямоугольной формы (по сравнению сksh
любым другим. Я говорю здесь до 10 раз медленнее - без шуток). Вы действительно хотите оптимизировать свои вилки (и не только) при работе с более крупными скриптами или огромными циклами.Нет!
Прежде всего, не имеет значения, где в команде происходит перенаправление. Так что, если вам нравится перенаправление слева от команды, ничего страшного:
такой же как
Во-вторых, при использовании канала происходит n + 1 процессов и подоболочка. Это определенно медленнее. В некоторых случаях n было бы равно нулю (например, когда вы перенаправляете на встроенную оболочку), поэтому при использовании
cat
вы добавляете новый процесс совершенно без необходимости.В качестве обобщения, всякий раз, когда вы обнаруживаете, что используете трубку, стоит потратить 30 секунд, чтобы посмотреть, сможете ли вы ее устранить. (Но, вероятно, не стоит занимать больше 30 секунд.) Вот несколько примеров, когда конвейеры и процессы часто используются без необходимости:
Не стесняйтесь редактировать, чтобы добавить больше примеров.
источник
< cat grep dog
это надуманный пример, чтобы показать, что вы не можете легко отличить входной файл от команды который получает ввод и аргументы команды.stdout=$(foo bar -exec baz <qux | ENV=VAR quux)
. Q. Имеет ли<qux
применять кfoo
, илиbaz
, что-exec
«г наfoo
? A. Это применимо кfoo
, но может показаться неоднозначным. Полагая ,<qux
прежде чемfoo
в этом случае является более ясным, хотя и менее распространенным, и аналогичен роспускнымENV=VAR quux
.<"cat" grep dog
легче читать. (Я обычно выступаю за пробелы, но этот конкретный случай - исключение).Я не согласен с большинством случаев чрезмерно самодовольной награды UUOC, потому что, обучая кого-то другого, он
cat
является удобным заполнителем для любой команды или жестко сложного конвейера команд, которые производят выходные данные, подходящие для обсуждаемой проблемы или задачи.Это особенно актуально для таких сайтов, как Stack Overflow, ServerFault, Unix и Linux, или любых других сайтов SE.
Если кто-то конкретно спрашивает об оптимизации, или если вы хотите добавить дополнительную информацию об этом, тогда отлично, поговорите о том, что использование cat неэффективно. Но не ругайте людей за то, что они предпочли стремиться к простоте и легкости понимания в своих примерах, а не смотреть-на-меня-как-круто-я-я! сложность.
Короче говоря, потому что кошка - это не всегда кошка.
Также потому, что большинство людей, которым нравится награждать UUOC, делают это потому, что они больше озабочены тем, чтобы показать, насколько они «умны», чем помогать или учить людей. На самом деле они демонстрируют, что они, вероятно, просто еще один новичок, нашедший крошечную палку, чтобы победить своих сверстников.
Обновить
Вот еще один UUOC, который я опубликовал в ответе на https://unix.stackexchange.com/a/301194/7696 :
Педанты UUOC сказали бы, что это UUOC, потому что легко можно установить по
$filter
умолчанию пустую строку и сделатьif
оператор,filter='| grep -v "^$"'
но ИМО, не вставляя вертикальный символ в$filter
, этот «бесполезный»cat
служит чрезвычайно полезной цели самодокументирования факта это$filter
вprintf
строке не просто еще один аргументsqlplus
, это необязательный выходной фильтр, выбираемый пользователем.Если есть необходимость в нескольких дополнительных выходных фильтрах, обработка опций может просто добавляться
| whatever
к ним$filter
так часто, как это необходимо - один дополнительныйcat
в конвейере не повредит чему-либо или вызовет заметную потерю производительности.источник
==
внутри[ ]
не указано в POSIX, и не все реализации его принимают. Стандартизированный оператор просто=
.В версии UUoC
cat
необходимо прочитать файл в памяти, затем записать его в канал, а команда должна прочитать данные из канала, поэтому ядру нужно скопировать весь файл три раза, тогда как в случае перенаправления ядру нужно только один раз скопировать файл. Быстрее сделать что-то один раз, чем трижды.С помощью:
- это совершенно другое и не обязательно бесполезное использование
cat
. По-прежнему бесполезно, если команда представляет собой стандартный фильтр, который принимает ноль или более аргументов имени файла и обрабатывает их по очереди. Рассмотримtr
команду: это чистый фильтр, который игнорирует или отклоняет аргументы имени файла. Чтобы передать ему несколько файлов, вы должны использовать,cat
как показано. (Конечно, отдельно обсуждается, что дизайнtr
не очень хорош; нет реальной причины, по которой он не мог быть разработан как стандартный фильтр.) Это также может быть справедливо, если вы хотите, чтобы команда обрабатывала все входные данные как один файл, а не как несколько отдельных файлов, даже если команда будет принимать несколько отдельных файлов: например,wc
такая команда.Это
cat single-file
дело безоговорочно бесполезное.источник
В защиту кота:
Да,
или
более эффективен, но многие вызовы не имеют проблем с производительностью, поэтому вам все равно.
эргономические причины:
Мы привыкли читать слева направо, поэтому такая команда, как
легко понять.
должен перепрыгнуть через процесс1, а затем прочитать слева направо. Это можно вылечить:
выглядит как-то, как будто есть стрелка, указывающая влево, где ничего нет. Более запутанный и похожий на причудливое цитирование выглядит так:
и создание скриптов часто является итеративным процессом,
где вы видите свой прогресс пошагово, а
даже не работает. Простые способы менее подвержены ошибкам, а эргономичная цепочка команд упрощается с помощью cat.
Другая тема заключается в том, что большинство людей сталкивались с операторами сравнения> и <как задолго до использования компьютера, а при использовании компьютера в качестве программистов гораздо чаще сталкиваются с ними как таковыми.
И сравнение двух операндов с <и> является противоположным коммутативным, что означает
Я помню, как впервые использовал <для перенаправления ввода, я боялся
может означать то же, что и
и как-то перезаписать мой скрипт a.sh. Возможно, это проблема многих новичков.
редкие отличия
Последний можно использовать непосредственно в расчетах.
Конечно, здесь также можно использовать <вместо параметра файла:
а кого это волнует - 15к?
Если бы я время от времени сталкивался с проблемами, я бы наверняка изменил свою привычку призывать кошку.
При использовании очень больших или многих, многих файлов можно избежать cat. На большинство вопросов использование кошки ортогонально, не по теме, не проблема.
Начинать это бесполезное бесполезное обсуждение каждой второй темы оболочки только утомительно и скучно. Получите жизнь и дождитесь своей минуты славы, решая вопросы производительности.
источник
file > a.sh
стоит того, чтобы потратить время на чтение этого :) Спасибо, что поделились!cat file | wc -c
,wc
нужно читать не стандартный ввод до конца файла, подсчет байт. Но в этом случаеwc -c < file
он просто stdin определяет, что это обычный файл, и печатает st_size вместо чтения любого ввода. Для большого файла будет отчетливо видна разница в производительности.Дополнительная проблема заключается в том, что канал может незаметно маскировать подоболочку. В этом примере я заменю
cat
наecho
, но существует та же проблема.Вы могли бы ожидать
x
сдерживанияfoo
, но это не так.x
Вы сет в подоболочке порождала выполнитьwhile
петлю.x
в оболочке, запустившей конвейер, имеет несвязанное значение или вообще не задано.В bash4 вы можете настроить некоторые параметры оболочки так, чтобы последняя команда конвейера выполнялась в той же оболочке, что и та, которая запускает конвейер, но затем вы можете попробовать это
и
x
снова является локальным дляwhile
подоболочки.источник
shopt -s lastpipe
избегать создания подоболочки.Как человек, регулярно указывающий на этот и ряд других антипаттернов программирования оболочки, я чувствую себя обязанным с опозданием взвесить все.
Сценарий оболочки - это во многом язык копирования / вставки. Большинство людей, которые пишут сценарии оболочки, не хотят изучать язык; это просто препятствие, которое они должны преодолеть, чтобы продолжать делать что-то на языке (ах), с которым они в некоторой степени знакомы.
В этом контексте я считаю подрывным и потенциально даже разрушительным распространение различных антишаблонов сценариев оболочки. Код, который кто-то находит в Stack Overflow, в идеале должен иметь возможность копировать / вставлять в свою среду с минимальными изменениями и неполным пониманием.
Среди множества ресурсов сценариев оболочки в сети, Stack Overflow необычен тем, что пользователи могут помочь сформировать качество сайта, редактируя вопросы и ответы на сайте. Однако редактирование кода может быть проблематичным, потому что легко вносить изменения, которые не были запланированы автором кода. Поэтому мы склонны оставлять комментарии, чтобы предложить изменения в коде.
Комментарии UUCA и связанные с ними антипаттерны предназначены не только для авторов кода, который мы комментируем; они являются такой же риск покупателя для помощи читателей сайта стало известно о проблемах в коде они находят здесь.
Мы не можем надеяться на достижение ситуации, когда ни один из ответов на Stack Overflow не рекомендует бесполезные
cat
s (или переменные без кавычек, илиchmod 777
, или большое количество других антипаттернов), но мы можем, по крайней мере, помочь обучить пользователя, который собирается скопировать / вставьте этот код в самый внутренний жесткий цикл их скрипта, который выполняется миллионы раз.Что касается технических причин, традиционная мудрость состоит в том, что мы должны стараться минимизировать количество внешних процессов; это остается хорошим общим руководством при написании сценариев оболочки.
источник
cat
- это множество дополнительных переключателей контекста и пропускной способности памяти (и загрязнение кеша L3 дополнительными копиями данных вcat
буфере чтения и буферах конвейера). Пропускная способность кеша / памяти является общим ресурсом, особенно на большой многоядерной машине (например, на многих хостингах).bzip2
иgzip
сжатие выполняются очень медленно по сравнению с накладными расходами,cat
добавляемыми только к этому (в противном случае машина простаивает). Трудно читать ваши таблицы (перенос строки в середине числа?).sys
время сильно увеличивается, но все равно мало по сравнению с пользовательским или реальным?Я часто использую
cat file | myprogram
в примерах. Иногда меня обвиняют в бесполезном использовании кошки ( http://porkmail.org/era/unix/award.html ). Я не согласен по следующим причинам:Легко понять, что происходит.
При чтении команды UNIX вы ожидаете, что за командой последуют аргументы, за которыми следует перенаправление. Перенаправление можно разместить где угодно, но оно редко встречается - поэтому людям будет труднее читать пример. Я считаю
легче читать чем
Если вы переместите перенаправление в начало, вы запутаете людей, которые не привыкли к этому синтаксису:
и примеры должны быть легкими для понимания.
Легко изменить.
Если вы знаете, что программа может читать из
cat
, вы обычно можете предположить, что она может считывать вывод любой программы, которая выводит в STDOUT, и, таким образом, вы можете адаптировать ее для своих собственных нужд и получить предсказуемые результаты.Он подчеркивает, что программа не завершится ошибкой, если STDIN не является файлом.
Небезопасно предполагать, что если
program1 < foo
работает, тоcat foo | program1
тоже будет работать. Однако можно с уверенностью предположить обратное. Эта программа работает, если STDIN - это файл, но не работает, если вход представляет собой канал, потому что он использует поиск:Стоимость исполнения
Дополнительные расходы оплачиваются
cat
. Чтобы дать представление о том, сколько я провел несколько тестов для моделирования базовой (cat
), низкой пропускной способности (bzip2
), средней пропускной способности (gzip
) и высокой пропускной способности (grep
).Тесты проводились на младшей системе (0,6 ГГц) и обычном ноутбуке (2,2 ГГц). Они были запущены по 10 раз в каждой системе, и было выбрано лучшее время для имитации оптимальной ситуации для каждого теста. $ ISO был ubuntu-11.04-desktop-i386.iso. (Более красивые таблицы здесь: http://oletange.blogspot.com/2013/10/useless-use-of-cat.html )
Результаты показывают, что для низкой и средней производительности стоимость составляет порядка 1%. Это находится в пределах погрешности измерений, поэтому на практике нет никакой разницы.
Для высокой пропускной способности разница больше, и между ними есть явная разница.
Отсюда следует вывод:
<
вместоcat |
if следует использовать :В противном случае не имеет значения, используете ли вы
<
илиcat |
.Таким образом, вы должны присваивать UUoC-награду только тогда и только тогда, когда:
источник
Я думаю, что (традиционный способ) использование pipe немного быстрее; в моем ящике я использовал
strace
команду, чтобы узнать, что происходит:Без трубы:
И с трубкой:
Вы можете провести некоторое тестирование с помощью
strace
и, используяtime
все больше и больше команд для хорошего тестирования.источник
strace
показывает, что это быстрее - во втором случае выполнениеstrace
не отслеживаетсяwc -l
. Здесь отслеживается только первая команда конвейера.strace -f sh -c 'wc -l < wrong_output.c'
рядомstrace -f sh -c 'cat wrong_output.c | wc -l'
.cat
: ideone.com/2w1W42#stderrmkfifo
создает именованный канал. Анонимный канал устанавливается сpipe(2)
последующим разветвлением, и родитель и потомок закрывают разные концы канала. Но да, этот ответ - полная чушь, и он даже не пытался подсчитывать системные вызовы или использоватьstrace -O
для измерения накладных расходов или-r
для отметки времени каждого вызова относительно последнего ...