Команда для вывода содержимого файла на стандартный вывод?

28

Я знаю, catчто это можно сделать, но его главная цель - объединить, а не просто отобразить контент.

Я также знаю о lessи more, но я ищу что-то простое ( не пейджер ), которое просто выводит содержимое файла на терминал, и это сделано специально для этого, если есть такая вещь.

confused00
источник
1
На самом деле в 99% случаев вы используете cat для отображения файлов, а не для объединения чего-либо.
LatinSuD
1
@LatinSuD - 100% времени - catобъединяет.
mikeserv
@mikeserv: вопрос в том, что вы имеете в виду, выполняя операцию; нормальное использование языка подразумевало бы, что это сделано по крайней мере один раз. «Печать» пустой строки не требует печати каких-либо символов; было бы справедливо сказать, что это ничего не печатает. Теперь вычисление a+b+cвключает в себя выполнение 2 сложений, а вычисление aне требует добавления чего-либо. Точно так же выполнение cat fне требует объединения чего-либо (хотя это единственное, что может означать «объединение последовательности из одного файла»).
Марк ван Леувен
2
@mikeserv: Я не понимаю, что ты имеешь в виду под + out. Конечно, catчитает файл и записывает другой файл (поток), но это не значит, что он объединяет что-либо. Если вы, возможно, имеете в виду, что cat fна самом деле это делает cat - f, это просто неправда
Марк ван Леувен
1
@ confused00: catдействительно предназначался для объединения ( cat file1 file2объединит оба файла в стандартный вывод). Но побочным эффектом является то, что, когда в качестве аргумента используется только 1 файл, он выводит этот файл на стандартный вывод (куда бы он ни направлялся: либо на ваш терминал, либо на что-то перенаправленное). Таким образом, не было никакой другой команды, созданной только для вывода на стандартный вывод, поскольку она catсуществовала и позволяла это просто. Поэтому вы хотите использовать cat.
Оливье Дюлак

Ответы:

37

Самый очевидный из них cat. Но также посмотрите headи tail. Есть также другие utillities оболочки для печати файл построчно: sed, awk, grep. Но они должны чередовать содержимое файла или искать внутри файла.

Я сделал несколько тестов, чтобы оценить, какой из них наиболее эффективен. Я запускаю все корыта, straceчтобы увидеть, какие из них были наименьшими. Мой файл имеет 1275 строк.

  • awk: 1355 системных вызовов
  • cat: 51 системный вызов
  • grep: 1337 системных вызовов
  • head: 93 системных вызова
  • tail: 130 системных вызовов
  • sed: 1378 системных вызовов

Как видите, даже если catон предназначен для объединения файлов, он самый быстрый и эффективный. sed, awkИ grepнапечатал файл построчно, то почему они имеют более что 1275 системных вызовов.

хаос
источник
8
Хорошая идея посчитать системные вызовы!
января
1
+1, ответ более точный (о значении кота), более полный (альтернативы) и исследованный (системные вызовы)
Оливье Дюлак
23

Я знаю, catчто это можно сделать, но его главная цель - объединить, а не просто отобразить контент.

Цель catсостоит именно в том, чтобы прочитать файл и вывести его на стандартный вывод.

январь
источник
1
Но cat --helpговорит "Объединить ФАЙЛ (ы), или стандартный ввод, к стандартному выводу". Я не хочу ничего объединять
confused00
18
Хотите верьте, хотите нет, но кошка - это именно то, что вы ищете.
января
5
Нет, @ confused00, Ян прав. Дело в том, что терминал - это стандартный вывод - понимаете? сделайте, readlink /dev/fd/1например, - вы должны получить там имя вашего tty, если вы работаете в стандартном приглашении. Поэтому объединение ввода в вывод - это то, что вы просите сделать.
mikeserv
2
@mikeserv Да, я понимаю твою точку зрения, я думаю, я был слишком сосредоточен на значении «конкатенация».
confused00
3
Логика заключается в том, что печать содержимого одного файла - это просто особый случай печати содержимого одного или нескольких файлов в последовательности.
Звол
10

Сначала catвыполняется запись в стандартный вывод, который не обязательно является терминалом, даже если он catбыл введен как часть команды для интерактивной оболочки. Если вам действительно нужно что-то записать в терминал, даже если стандартный вывод перенаправлен, это не так просто (вам нужно указать, какой терминал, и может даже не быть, если команда выполняется из скрипта), хотя один может (ab) использовать стандартный вывод ошибок, если команда является просто частью конвейера. Но так как вы указали, что на catсамом деле выполняет свою работу, я полагаю, вы не спрашивали о такой ситуации.

Если ваша цель - отправить то, что записано в стандартный вывод, в конвейер, то использование catбудет иметь право на награду « Бесполезное использование Cat» , поскольку cat file | pipeline(где pipelineобозначает любой конвейер) можно сделать более эффективно, чем <file pipeline. Но опять же, из вашей формулировки я делаю вывод, что это не было вашим намерением.

Так что не очень понятно, о чем вы беспокоитесь. Если вы нашли catслишком длинный текст, вы можете определить одно- или двухсимвольный псевдоним (есть еще несколько таких имен, которые остаются неиспользованными в стандартном Unix). Однако, если вы беспокоитесь, что catтратите бесполезные циклы, вы не должны.

Если бы существовала программа, nullкоторая не принимает аргументов и просто копирует стандартный ввод в стандартный вывод (нейтральный объект для конвейеров), вы можете делать то, что хотите <file null. Такой программы не существует, хотя ее было бы легко написать (программа на языке C с помощью однострочной mainфункции может выполнить эту работу), но вызов catбез аргументов (или, cat -если вы хотите быть явным) делает именно это.

Если бы существовала nocatпрограмма, которая принимает ровно один аргумент имени файла, пытается открыть файл, жалуется на него, если не может, и в противном случае переходит к копированию из файла в стандартный вывод, тогда это будет именно то, что вы просите. Писать его немного сложнее, чем nullосновная работа: открытие файла, тестирование и, возможно, жалоба (если вы дотошны, вы можете также включить тест, в котором есть только один аргумент, и пожаловаться в противном случае). Но опять же cat, теперь с одним аргументом, это именно так, поэтому нет необходимости в какой-либо nocatпрограмме.

Если вам удалось написать nocatпрограмму, зачем останавливаться на одном аргументе? Заключение кода в цикл for(;*argp!=NULL;++argp)на самом деле совсем не сложно, добавляет в двоичный файл не более пары машинных инструкций и позволяет избежать необходимости жаловаться на неправильное количество аргументов (что избавляет от множества других инструкций). Вуаля примитивная версия cat, объединяющая файлы. (Если честно, нужно немного подправить его, чтобы без аргументов он вел себя как null.)

Конечно, в реальной catпрограмме они добавили несколько наворотов, потому что они всегда так делают. Но суть в том, что аспект «конкатенации» catзатрат вообще не требует усилий ни для программиста, ни для исполняющей его машины. Тот факт, что catподводит итог nullи nocatобъясняет отсутствие таких программ. Избегайте использования catс одним аргументом, если результат попадает в конвейер, но если он используется только для отображения содержимого файла на терминале, даже страница, на которую я ссылался, признает, что это полезное использование cat, так что не стесняйтесь.


Вы можете проверить, что catв действительности реализовано простым циклом вокруг гипетической nocatфункциональности, вызывая catнесколько имен файлов, среди которых одно недопустимое имя, а не в первой позиции: вместо того, чтобы сразу жаловаться, что этот файл не существует, catсначала сбрасывает предыдущий допустимые файлы, а затем жалуется на неверный файл (по крайней мере, так ведет себя моя кошка).

Марк ван Леувен
источник
7

При zshпопытке

<file

Я считаю, что это самый короткий способ напечатать файл. Он использует «скрытый» cat(или, moreесли stdout является терминалом), но команда, используемая для печати, управляется READNULLCMDпеременной, которую вы можете безопасно перезаписать непосредственно по имени команды или даже по какой-либо функции. Например, для печати файлов с нумерацией строк:

numcat() { nl -s'> ' -w2 - }
READNULLCMD=numcat
<file
jimmij
источник
5

POSIX определить кошку как:

НАЗВАНИЕ

cat - объединяет и печатает файлы

СИНТАКСИС

кошка [-u] [файл ...]

ОПИСАНИЕ

Утилита cat должна последовательно читать файлы и записывать их содержимое в стандартный вывод в той же последовательности.

Поэтому я думаю, что объединение здесь означает чтение файлов по порядку .

cuonglm
источник
5

Я знаю, что это вопрос прошедшего времени. Технически, поскольку печать содержимого файла stdoutявляется формой конкатенации, catэто семантически целесообразно. Не забывайте, что printfсемантически предназначен для форматирования и печати данных. Bash также предоставляет синтаксис для перенаправления ввода и вывода из файлов. Сочетание этого может привести к этому:

printf '%s' "$(<file.txt)"
Джеймс М. Лей
источник
4
Помимо того, что указанная команда является особенно обходной, отображаемая команда не эквивалентна cat file.txt, так как она удалит все завершающие символы новой строки (это $(...)делает).
Марк ван Леувен
+1, хороший улов. Не знал этого.
Джеймс М. Лей
3

Используя bashвстроенные функции и избегая создания подпроцесса:

{ while IFS='' read -rd '' _bcat_; do printf '%s\0' "${_bcat_}"; done; printf '%s' "${_bcat_}"; unset _bcat_; } <'/path/to/file'

IFSбудет применяться только к readкоманде, поэтому не беспокойтесь о ваших глобальных IFSизменениях.

Цикл необходим для обработки нулевых символов (спасибо Стефану Шазеласу).

Этот способ не подходит для больших файлов, потому что содержимое файла сначала читается в переменную (то есть в память). Кстати, я пытался напечатать текстовый файл 39M таким образом, и использование памяти bash не превышало 5M, поэтому не уверен насчет этого случая.

Он также чертовски медленный и неэффективный процессор: для того же файла 39M это заняло ~ 3 минуты при 100% использовании одного ядра.

Для больших файлов или двоичных файлов лучше использовать cat '/path/to/file'или даже, dd if='/path/to/file' bs=1Mесли это возможно.

Михаил
источник
1
Смотрите также, pv -qчто в Linux можно использовать, splice()что для некоторых типов stdin / stdout улучшит производительность.
Стефан Шазелас
1

Так же, как демонстрация, вы можете сделать

cp foo /dev/stdout
wisbucky
источник