Команда для виведення вмісту файлу в stdout?


28

Я знаю, catщо це можна зробити, але його головна мета - це об'єднання, а не просто показ вмісту.

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


1
Насправді у 99% випадків, коли ви використовуєте cat, це відображати файли, а не об'єднувати що-небудь.
LatinSuD

1
@LatinSuD - 100% часу - catконкатенати.
mikeserv

@mikeserv: Це питання про те, що ви маєте на увазі під операцією; нормальне використання мови означає, що це робиться принаймні один раз. "Друк" порожнього рядка не передбачає друку жодних символів; було б справедливо сказати, що вона нічого не друкує. Зараз обчислення a+b+cвключає виконання двох доповнень, а обчислення aне передбачають додавання нічого. Аналогічно виконання cat fне передбачає об'єднання нічого (навіть якщо це єдине, що може "означати послідовність одного файлу").
Марк ван Левен

2
@mikeserv: Я не розумію, що ви маєте на увазі як у + вихід. Звичайно catчитає файл і записує інший файл (потік), але це не означає, що він об'єднує щось. Якщо ви, можливо, маєте на увазі, що cat fнасправді це cat - fробиться, це просто неправда.
Марк ван Левенен

1
@ confused00: catдійсно мав на меті об'єднати ( cat file1 file2об'єднає обидва файли в stdout). Але побічним ефектом є те, що, маючи лише один файл як аргумент, він видає один файл stdout (куди б це не було, або ваш термінал, або перенаправлений на щось). Отже, не було жодної іншої команди, створеної просто для виведення на stdout, як вона 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полягає саме в тому, щоб прочитати файл і вивести в stdout.


1
Але cat --helpговорить "З'єднати ФАЙЛ (и) або стандартний вхід до стандартного виводу". Я не хочу нічого об'єднувати
плутати00

18
Вірите чи ні, кішка - це саме те, що ви все одно шукаєте.
січня

5
Ні, @ confused00, право Яна. Справа в тому , - термінал є стандартним висновком - ви бачите? зробіть, readlink /dev/fd/1наприклад, - вам слід ввести ім'я вашого tty там, якщо він працює за стандартним підказкою. Так що ви просите зробити об'єднання вводу на вихід.
mikeserv

2
@mikeserv Так, я бачу вашу думку, я гадаю, що я занадто сильно сформулювався на значенні "з'єднати".
плутати00

3
Логіка полягає в тому, що друк вмісту одного файлу - це лише особливий випадок друку вмісту одного або декількох файлів послідовно.
zwol

10

По-перше, catзаписує на стандартний вихід, який не обов'язково є терміналом, навіть якщо він catбув введений як частина команди в інтерактивну оболонку. Якщо вам дійсно потрібно щось написати в термінал, навіть коли стандартний вихід перенаправлений, це не так просто (вам потрібно вказати, який термінал, а може бути навіть і один, якщо команда виконується зі сценарію), хоча один може (ab) використовувати стандартний вихід помилок, якщо команда є лише частиною конвеєра. Але оскільки ви вказали, що 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)насправді зовсім не докладає зусиль, додає до двійкового файлу максимум пару машинних інструкцій і уникає того, щоб скаржитися на неправильну кількість аргументів (що дозволяє набагато більше інструкцій). Voilà - примітивна версія 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

5

POSIX визначають кішку як:

ІМ’Я

cat - об'єднання та друк файлів

СИНОПИС

cat [-u] [файл ...]

ОПИС

Утиліта кішок читає файли послідовно та записує їх вміст на стандартний вихід у тій же послідовності.

Тому я думаю, що об'єднати тут означає читання файлів послідовно .


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зміни.

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

Цей спосіб не підходить для великих файлів, оскільки вміст файлу спочатку зчитується до змінної (тому пам'яті). BTW Я намагався надрукувати 39M текстовий файл таким чином, і використання оперативної пам’яті не перевищувало 5 М, тому не впевнений у цьому випадку.

Це також чортово повільно і неефективно CPU: для того самого 39M-файлу знадобилося ~ 3 хвилини зі 100% використанням одного ядра.

Для великих файлів або двійкових файлів краще використовувати cat '/path/to/file'або навіть, dd if='/path/to/file' bs=1Mякщо можливо.


1
Дивіться також, pv -qякі в Linux можуть використовувати, splice()що для деяких типів stdin / stdout покращить продуктивність.
Стефан Хазелас

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.