Многие утилиты командной строки могут получать свои данные либо из канала, либо в качестве аргумента имени файла. Для длинных сценариев оболочки, я считаю, что начало цепочки с помощью cat
делает ее более читаемой, особенно если первая команда будет нуждаться в многострочных аргументах.
сравнить
sed s/bla/blaha/ data \
| grep blah \
| grep -n babla
а также
cat data \
| sed s/bla/blaha/ \
| grep blah \
| grep -n babla
Последний метод менее эффективен? Если да, то достаточно ли разницы, чтобы заботиться о том, запускается ли скрипт, скажем, раз в секунду? Разница в читаемости не огромна.
shell-script
performance
pipe
cat
tshepang
источник
источник
cat
. Однако я думаю, что главный вопрос здесь - читаемость кода, которая часто является приоритетом перед производительностью. Когда быстрее можно написать красивее , почему бы и нет? Указание на проблемуcat
обычно приводит к тому, что пользователь лучше понимает конвейеры и процессы в целом. Это стоит того, чтобы в следующий раз они написали понятный код.cat
; точка зрения Калеба об использовании функций и перенаправления также решает эту проблему.)Ответы:
«Окончательный» ответ, конечно же, принес вам «Бесполезное использование
cat
награды» .Инстанцирование cat просто так, что ваш код читает по-разному, делает еще один процесс и еще один набор потоков ввода / вывода ненужными. Как правило, реальная задержка в ваших скриптах - это неэффективные циклы и фактическая обработка. В большинстве современных систем одна дополнительная функция
cat
не приведет к снижению производительности, нопочтивсегда есть другой способ написания кода.Как вы заметили, большинство программ могут принимать аргумент для входного файла. Однако всегда есть встроенная оболочка,
<
которую можно использовать везде, где ожидается поток STDIN, который сэкономит вам один процесс, выполнив работу в уже запущенном процессе оболочки.Вы даже можете проявить творческий подход, ГДЕ вы пишете. Обычно это будет помещено в конец команды, прежде чем вы укажете какие-либо перенаправления вывода или каналы, как это:
Но так не должно быть. Это может даже прийти первым. Например, ваш пример кода может быть написан так:
Если читаемость сценария является вашей проблемой, а ваш код достаточно запутан, и
cat
ожидается , что добавление строки для облегчения его отслеживания, существуют другие способы очистки кода. Я часто использую то, что помогает сделать сценарии более простыми для понимания в дальнейшем, - это разбиение каналов на логические наборы и сохранение их в функциях. Код сценария становится очень естественным, и любую часть трубопровода легче отлаживать.Затем вы можете продолжить
fix_blahs < data | fix_frogs | reorder | format_for_sql
. Пипллайн, который читается так, очень легко следовать, и отдельные компоненты могут быть легко отлажены в своих соответствующих функциях.источник
<file
может прийти раньше команды. Это решает все мои проблемы!<file
может находиться в любом месте командной строки:<file grep needle
илиgrep <file needle
илиgrep needle <file
. Исключение составляют сложные команды, такие как циклы и группировки; там перенаправление должно наступить после закрытияdone
/}
/)
/ etc. @Caleb Это относится ко всем оболочкам Bourne / POSIX. И я не согласен, что это некрасиво.$(cat /some/file)
на$(< /some/file)
, что делает то же самое, но избегает порождения процесса.$(< /some/file)
это ограниченная мобильность. Он работает в bash, но не в BusyBox, например, в FreeBSD sh. Вероятно, не работает в тире, так как эти последние три снаряда все близкие родственники.Вот краткое изложение некоторых недостатков:
над
$file
. В случаеcat
, это всегда проблема, за исключениемzsh
; в случае перенаправления это проблема только дляbash
или,ksh88
а для некоторых других оболочек только в интерактивном режиме (не в сценариях).cmd
встроен, это даже 2 процесса в некоторых оболочках, какbash
.cat
встроенных оболочек , в которых также выполняется дополнительная команда (и, конечно, она загружается и инициализируется (и библиотеки, с которыми она связана)).cat
иcmd
процессы и постоянно пополняет и опустошение буфера трубы. Даже если за один разcmd
выполняются1GB
большиеread()
системные вызовы, управление должно идти назад и вперед междуcat
иcmd
потому, что канал не может хранить более нескольких килобайт данных за раз.cmd
s (напримерwc -c
) могут выполнять некоторую оптимизацию, когда их стандартный stdin - это обычный файл, с которым они не могут работать, такcat | cmd
как их стандартный stdin - это просто канал. Сcat
и труба, это также означает, что они не могутseek()
в файле. Для таких команд, какtac
илиtail
, это имеет огромное значение для производительности, так как это означает, чтоcat
они должны хранить весь ввод в памяти.cat $file
даже его более правильная версияcat -- "$file"
не будет работать должным образом для некоторых конкретных имен файлов, таких как-
(--help
или что-нибудь, начиная с,-
если вы забудете--
). Если кто-то настаивает на использованииcat
, он, вероятно, должен использоватьcat < "$file" | cmd
вместо этого для надежности.$file
не может быть открыт для чтения (доступ запрещен, не существует ...),< "$file" cmd
сообщит о непротиворечивом сообщении об ошибке (оболочкой) и не запуститсяcmd
, покаcat $file | cmd
будет работать,cmd
но с его stdin, похожим на пустой файл. Это также означает, что в таких вещах, как< file cmd > file2
,file2
не засоряется, еслиfile
не может быть открыт.источник
truncate -s10G a; time wc -c < a; time cat a | wc -c; time cat a | cat | wc -c
. Есть много параметров, которые входят в картину. Падение производительности может составлять от 0 до 100%. В любом случае, я не думаю, что штраф может быть отрицательным.wc -c
это довольно уникальный случай, потому что он имеет ярлык. Если вы вместо этого сделаете это,wc -w
то это сравнимо сgrep
моим примером (т. Е. Очень мало обработки - то есть ситуация, когда «<» может иметь значение).wc -w
для разреженного файла объемом 1 ГБ в локали C на linux 4.9 amd64) я обнаружил, что подход cat занимает больше времени на 23% в многоядерной системе и 5% при привязке их к одному ядру. Показаны дополнительные издержки, связанные с доступом к данным более чем одним ядром. Возможно, вы получите другие результаты, если вы измените размер канала, будете использовать разные данные, задействуете реальный ввод-вывод, используйте реализацию cat, которая использует splice () ... Все это подтверждает, что на рисунке много параметров. и это в любом случаеcat
не поможет.wc -w
это разница примерно в 2% ... 15%, если это просто простой grep. Затем, как ни странно, если он находится в общем файловом ресурсе NFS, на самом деле он читается на 20% быстрее, если передается по каналуcat
( gist.github.com/rdp/7162414833becbee5919cda855f1cb86 ) Странно ...Помещение
<file
в конец конвейера менее читабельно, чемcat file
в начале. Естественный английский читает слева направо.Ввод
<file
начало трубопровода также менее читабельным , чем кошки, я бы сказал. Слово более читабельно, чем символ, особенно символ, который, кажется, указывает неправильный путь.Использование
cat
сохраняетcommand | command | command
формат.источник
<
одного раза делает код менее читаемым, так как это нарушает синтаксическую согласованность многопоточной линии.<
подобный этому:alias load='<'
и затем используйте напримерload file | sed ...
. Псевдонимы могут использоваться в скриптах после запускаshopt -s expand_aliases
.Одна вещь, на которую другие ответы здесь, похоже, не имеют прямого отношения, заключается в том, что такое использование
cat
не является «бесполезным» в том смысле, что «возникает процесс постороннего кота, который не работает»; это бесполезно в том смысле, что «создается процесс кошки, который выполняет только ненужную работу».В случае этих двух:
оболочка запускает процесс sed, который читает из somefile или stdin (соответственно), а затем выполняет некоторую обработку - он читает до попадания на новую строку, заменяет первый «foo» (если есть) в этой строке на «bar», затем печатает эта строка в стандартный вывод и петли.
На случай, если:
Оболочка порождает процессы cat и sed, и подключает stdout cat к stdin sed. Процесс cat считывает фрагмент из нескольких килобайт или, возможно, мегабайт, из файла, а затем записывает это в свой стандартный вывод, откуда оттуда берется команда sed, как во втором примере выше. Пока sed обрабатывает этот чанк, cat читает другой чанк и записывает его в свой стандартный вывод, чтобы sed мог продолжить работу с ним.
Другими словами, дополнительная работа, необходимая для добавления
cat
команды, - это не просто дополнительная работа по созданию дополнительногоcat
процесса, это также дополнительная работа по чтению и записи байтов файла дважды, а не один раз. Теперь, если говорить практически и на современных системах, это не имеет большого значения - это может заставить вашу систему выполнить несколько микросекунд ненужной работы. Но если это сценарий, который вы планируете распространять, возможно, людям, использующим его на машинах, которые уже недостаточно загружены, несколько микросекунд могут сложиться за много итераций.источник
cat
.cat
делением на мс безcat
процентов (например, 264 мс / 216 мс = 1,22 = 122% = 22% медленнее сcat
)