Продолжая экскурсию по командам в Linux, рассмотрим сегодня команду cat
.
Название cat
расшифровывается как catenate
, основная задача этой команды является объединение нескольких входных файлов путем последовательной отправки их содержимого на стандартный вывод:
# Давайте сначала получим некоторые примеры файлов данных:
curl -so - dict://dict.org/'d:andreyex:gcide' | unexpand -a -t 3 |
sed -Ee '/^151/,/^[.]/!d;/^[.0-9]/s/.*//' > andreyex.txt
curl -so - dict://dict.org/'d:ubuntu:gcide' | unexpand -a -t 3 |
sed -Ee '/^151/,/^[.]/!d;/^[.0-9]/s/.*//' > ubuntu.txt
# Объединение файлов
cat andreyex.txt ubuntu.txt
Если вы хотите сохранить результат этой конкатенации в файле, вам необходимо использовать перенаправление оболочки:
cat andreyex.txt ubuntu.txt > result.txt
cat result.txt
Даже если основной целью проекта является объединение файлов, утилита cat
также часто используется только с одним аргументом для отображения содержимого этого файла на экране, точно так же, как мы это сделали в последней строке примера выше.
A. Использование команды cat со стандартным входом
При использовании без каких-либо аргументов команда cat
будет считывать данные со своего стандартного ввода и записывать их на свой стандартный вывод, что в основном бесполезно … если вы не используете какой-либо параметр для преобразования данных. Мы поговорим о нескольких интересных вариантах позже.
В дополнение к пути к файлам, команда cat
также понимает -
специальное имя файла как псевдоним для стандартного ввода. Таким образом, вы можете вставить данные, считанные со стандартного ввода между файлами, указанными в командной строке:
# Вставить разделитель между двумя соединенными файлами
echo '----' | cat ubuntu.txt - andreyex.txt
B. Использование команды cat с двоичными файлами
1. Объединение разделенных файлов
Команда cat
не делает никаких предположений о содержимом файла, поэтому она будет работать с двоичными данными. Что-то, что может быть полезно, для объединения файлов разбитых с помощью команд split
или csplit
. Или присоединить к частичным загрузкам, как мы это сейчас сделаем:
#
# Изображение AndreyEx (CC-SA 3.0)
# Оптимизировать использование полосы пропускания, разбив загрузку на две части
# (в нашей системе мы наблюдаем 10%-ный прирост по сравнению с "полной" загрузкой)
curl -s -r 0-50000 \
https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Felis_catus-cat_on_snow.jpg/1024px-Felis_catus-cat_on_snow.jpg \
-o first-half &
curl -s -r 50001- \
https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Felis_catus-cat_on_snow.jpg/1024px-Felis_catus-cat_on_snow.jpg \
-o second-half &
wait
У нас теперь две половины изображения. Вы можете открыть первую половину и увидеть, что она «сломана» с помощью ImageMagick, display
, gimp
, или любого другого программного обеспечения, способного читать файлы изображений:
display first-half
# -или-
gimp first-half
# -или-
firefox first-half
Если вы изучите команду curl, которую мы использовали, вы увидите, что две части прекрасно дополняют друг друга. Первая половина – от 0 байт до 50000, а вторая половина – от 50001 байта до конца файла. Между ними не должно быть недостающих данных. Поэтому нам нужно только связать две части вместе (в правильном порядке), чтобы вернуть полный файл:
cat first-half second-half > image.jpg
display image.jpg
2. Работа с потоковыми форматами файлов
Вы можете не только использовать команду cat
для «воссоединения» двоичных файлов, которые были разделены на несколько частей, в некоторых случаях вы также можете создавать новые файлы таким образом. Это особенно хорошо работает с «без заголовка» или «потоковыми» файловыми форматами, такими как видеофайлы (файлы .TS
) транспортного потока MPEG :
# Давайте сделаем еще видео файл с нашего изображения
ffmpeg -y -loop 1 -i cat.jpg -t 3 \
-c:v libx264 -vf scale=w=800:h=-1 \
still.ts
# Давайте сделаем fade-in из того же изображения
ffmpeg -y -loop 1 -i cat.jpg -t 3 \
-c:v libx264 -vf scale=w=800:h=-1,fade=in:0:75 \
fadein.ts
# Давайте сделаем затухание из того же изображения
ffmpeg -y -loop 1 -i cat.jpg -t 3 \
-c:v libx264 -vf scale=w=800:h=-1,fade=out:0:75 \
fadeout.ts
Теперь мы можем комбинировать все эти видеопотоки с потоком данных с помощью команды cat
, получив в выходном файле абсолютно корректный TS-файл:
cat fadein.ts still.ts fadeout.ts > video.ts
mplayer video.ts
Благодаря формату файла TS вы можете объединить эти файлы в том порядке, который вы хотите, и вы даже можете использовать один и тот же файл несколько раз в списке аргументов для создания циклов или повторения в выходном видео. Очевидно, это было бы забавно, если бы мы использовали анимированные изображения, но сможете ли вы сделать это самостоятельно: многие устройства потребительского класса записывают файлы TS, а если нет, вы все равно можете использовать ffmpeg
для конвертирования практически любого видеофайла в файл транспортного потока. Не стесняйтесь делиться своими творениями, используя раздел комментариев!
3. Взлом cpio-архивов
В качестве последнего примера давайте посмотрим, как мы можем использовать команду cat
для объединения нескольких архивов cpio
. Но на этот раз это будет не так просто, поскольку для этого потребуется немного знаний о формате архивного файла cpio
.
В архиве cpio
хранятся метаданные и содержимое файла последовательно, что делает его подходящим для конкатенации файла с помощью утилиты cat
. К сожалению, в архиве cpio
также есть контейнер, используемый для обозначения конца архива:
# Создать два подлинных CPIO` bin ' архива:
$ find ubuntu.txt andreyex.txt | cpio -o > part1.cpio
2 blocks
$ echo cat.jpg | cpio -o > part2.cpio
238 blocks
$ hexdump -C part1.cpio | tail -7
000002d0 2e 0d 0a 09 09 20 20 5b 57 6f 72 64 4e 65 74 20 |..... [WordNet |
000002e0 31 2e 35 5d 0d 0a 0a 00 c7 71 00 00 00 00 00 00 |1.5].....q......|
000002f0 00 00 00 00 01 00 00 00 00 00 00 00 0b 00 00 00 |................|
00000300 00 00 54 52 41 49 4c 45 52 21 21 21 00 00 00 00 |..TRAILER!!!....|
00000310 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000400
$ hexdump -C part2.cpio | tail -7
0001da40 46 96 ab f8 ad 11 23 90 32 79 ac 1f 8f ff d9 00 |F.....#.2y......|
0001da50 c7 71 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |.q..............|
0001da60 00 00 00 00 0b 00 00 00 00 00 54 52 41 49 4c 45 |..........TRAILE|
0001da70 52 21 21 21 00 00 00 00 00 00 00 00 00 00 00 00 |R!!!............|
0001da80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
0001dc00
Хорошо является то, что двоичный архив cpio, этот контейнер с фиксированной длиной 280 байтов. Итак, используя стандартную команду head, у нас есть простой способ ее удалить:
# Каждый архив заканчивается 280-байтовым контейнером.
# Для catenate оба архива, просто убрать контейнер
# в конце первой части:
$ head -c-280 part1.cpio | cat - part2.cpio > cat.cpio
$ cpio -it < cat.cpio
ubuntu.txt
andreyex.txt
cat.jpg
239 blocks
C. Основные параметры команды cat
После того, как вы поиграли с различными форматами двоичных файлов, вернемся к простым старым текстовым файлам, изучив пару опций, специально предназначенных для работы с этими файлами. Несмотря на то, что они не являются частью стандарта POSIX, эти параметры являются переносимыми по версиям BSD и GNU для cat
. Обратите внимание: мы не претендуем на то, что мы здесь разберем все моменты, поэтому проверьте страницу man
, чтобы увидеть полный список опций, поддерживаемых вашей системой команду cat
!
-n
: числовые строки
С помощью опции n
команда cat
префикс каждой выходной строки по номеру строки:
cat -n andreyex.txt
1
2 andreyex \andreyex\ n.
3 a natural family of lithe-bodied round-headed fissiped
4 mammals, including the cats; wildcats; lions; leopards;
5 cheetahs; and saber-toothed tigers.
6
7 Syn: family {andreyex}.
8 [WordNet 1.5]
9
В параметр -n
число выходных линий. Это означает, что счетчик не сбрасывается при переходе от одного входного файла в другой, как вы увидите это, если вы попробовали самостоятельно следующую команду:
cat -n feli*.txt
-s
: подавление повторяющихся пустых выходных строк
С помощью опции -s
команда cat
сбрасывает несколько последовательных пустых строк:
cat -n ubuntu.txt andreyex.txt | sed -n 8,13p
8 lynx ({ubuntu lynx}) is also called {Lynx lynx}.
9 [1913 Webster +PJC]
10
11
12 andreyex \andreyex\ n.
13 a natural family of lithe-bodied round-headed fissiped
sylvain@bulbizarre:~$ cat -ns ubuntu.txt andreyex.txt | sed -n 8,13p
8 lynx ({ubuntu lynx}) is also called {Lynx lynx}.
9 [1913 Webster +PJC]
10
11 andreyex \andreyex\ n.
12 a natural family of lithe-bodied round-headed fissiped
13 mammals, including the cats; wildcats; lions; leopards;
В приведенном выше примере вы можете увидеть, что в выводе по умолчанию строки 10 и 11 были пустыми. При добавлении опции -s
вторая пустая строка была отброшена.
-b
: число только непустые строки
Несколько связанный с двумя предыдущими вариантами, опция -b
будет содержать строки, игнорируя пустые:
$ cat -b andreyex.txt | cat -n
1
2 1 andreyex \andreyex\ n.
3 2 a natural family of lithe-bodied round-headed fissiped
4 3 mammals, including the cats; wildcats; lions; leopards;
5 4 cheetahs; and saber-toothed tigers.
6 5
7 6 Syn: family {andreyex}.
8 7 [WordNet 1.5]
9
В приведенном выше примере используются два экземпляра команды cat
с различными параметрами в контейнере. Внутренняя нумерация происходит с помощью опции -b
, используемой с первой командой cat
. Внешняя нумерация исходит с помощью опции -n
, используемой со второй командой cat
.
Как вы можете увидеть, первая и последняя строки не были пронумерованы опцией -b
, потому что они пусты. Но как насчет 6-й линии? Почему она по-прежнему нумеруется с опцией -b
? Ну, потому что это строка заполненная пробелами, но не пустая, как мы увидим в следующем разделе.
-v
,,-e
, -t
: Отображение непечатаемых символов
Три варианта,-v
, -e `, and `-t
которые используются для отображения различных наборов невидимых символов. Даже если наборы перекрываются, нет опции «catch-all», поэтому вам придется комбинировать их, если вы хотите отображать все невидимые символы.
-v
: просмотр невидимых символов
Опция -v
отображает все непечатаемые символы с кареткой и мета – обозначениями, за исключением строки и табуляции.
С помощью этой опции управляющие символы будут отображаться как каретка ( ^
), за которыми следует соответствующий символ ASCII (например, возврат каретки, 13 байт отображается так, ^M
как M
в ASCII – 64 + 13), а символы с набором бит высокого порядка появится в «мета» описании M-
за которой следует представление, соответствующее 7 младшим битам (например, байт 141 будет отображаться так, M-^M
как 141 – 128 + 13).
Хотя, казалось бы, эзотерическая, эта функция может быть полезна при работе с двоичными файлами, например, если вы хотите изучить необработанную информацию, встроенную в файл JPEG:
$ cat -v cat.jpg | fold -75 | head -10
M-^?M-XM-^?M-`^@^PJFIF^@^A^A^A^@H^@H^@^@M-^?M-~^@QFile source: http://commo
ns.wikimedia.org/wiki/File:Felis_catus-cat_on_snow.jpgM-^?M-b^LXICC_PROFILE
^@^A^A^@^@^LHLino^B^P^@^@mntrRGB XYZ ^GM-N^@^B^@ ^@^F^@1^@^@acspMSFT
^@^@^@^@IEC sRGB^@^@^@^@^@^@^@^@^@^@^@^@^@^@M-vM-V^@^A^@^@^@^@M-S-HP ^@^@^
@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
^@^@^@^@^@^@^@^Qcprt^@^@^AP^@^@^@3desc^@^@^AM-^D^@^@^@lwtpt^@^@^AM-p^@^@^@^
Tbkpt^@^@^B^D^@^@^@^TrXYZ^@^@^B^X^@^@^@^TgXYZ^@^@^B,^@^@^@^TbXYZ^@^@^B@^@^@
^@^Tdmnd^@^@^BT^@^@^@pdmdd^@^@^BM-D^@^@^@M-^Hvued^@^@^CL^@^@^@M-^Fview^@^@^
CM-T^@^@^@$lumi^@^@^CM-x^@^@^@^Tmeas^@^@^D^L^@^@^@$tech^@^@^D0^@^@^@^LrTRC^
@^@^D<^@^@^H^LgTRC^@^@^D<^@^@^H^LbTRC^@^@^D<^@^@^H^Ltext^@^@^@^@Copyright (
Другим вариантом использования этого параметра -v
является поиск управляющих символов, которые могли бы просочиться в текстовый файл. Если вы запомнили это, у нас есть эта странная проблема выше с вариантом,-b
, обозначающим 6-ю строку ввода, тогда как она выглядела пустой. Итак, давайте расследуем следующее:
$ cat -v andreyex.txt
andreyex \andreyex\ n.^M
a natural family of lithe-bodied round-headed fissiped^M
mammals, including the cats; wildcats; lions; leopards;^M
cheetahs; and saber-toothed tigers.^M
^M
Syn: family {andreyex}.^M
[WordNet 1.5]^M
Ах ах! Вы видите эти знаки ^M
? Они используются для замены символа обратной невидимой каретки. Откуда это? Ну, протокол,dict
, как и любой другой интернет-протокол, использует CRLF в качестве терминатора линии. Поэтому мы загрузили их как часть наших образцовых файлов. Но пока это объясняет, почему cat
считает, что 6-я строка не пуста.
-e
: отображение невидимых символов, включая конец строки
Опция -e
работает с опцией -v
, только будет добавить знак доллара ($
) перед каждым символом перевода строки, тем самым явно показывая конец линии:
$ cat -e andreyex.txt
$
andreyex \andreyex\ n.^M$
a natural family of lithe-bodied round-headed fissiped^M$
mammals, including the cats; wildcats; lions; leopards;^M$
cheetahs; and saber-toothed tigers.^M$
^M$
Syn: family {andreyex}.^M$
[WordNet 1.5]^M$
$
-t
: отображение невидимых символов, включая вкладки
Опция -t
работает как вариант -v
, за исключением того, что будет также отображать табличные данные с помощью курсора ^I
(закладка хранится в виде байта удержания значение 9, а I
в ASCII составляет 64 + 9 = 73):
$ cat -t andreyex.txt
andreyex \andreyex\ n.^M
^Ia natural family of lithe-bodied round-headed fissiped^M
^Imammals, including the cats; wildcats; lions; leopards;^M
^Icheetahs; and saber-toothed tigers.^M
^M
^ISyn: family {andreyex}.^M
^I^I [WordNet 1.5]^M
-et
: показать все скрытые символы
Как мы уже говорили кратко, если вы хотите отобразить все непечатаемые символы, в том числе таблицы и маркеры конца строки, вам нужно будет использовать варианты -e
и -t
:
$ cat -et andreyex.txt
$
andreyex \andreyex\ n.^M$
^Ia natural family of lithe-bodied round-headed fissiped^M$
^Imammals, including the cats; wildcats; lions; leopards;^M$
^Icheetahs; and saber-toothed tigers.^M$
^M$
^ISyn: family {andreyex}.^M$
^I^I [WordNet 1.5]^M$
$
Бонус: бесполезное использование команды cat в Linux
Никакая статья о команде cat
не была бы полной без упоминания об использовании анти-шаблона «Бесполезное использование cat».
Это происходит, когда вы используете cat
, для единственной цели отправки содержимого файла на стандартный ввод другой команды. Это использование команды cat
называется «бесполезным», поскольку простой параметр перенаправления или имени файла выполнил бы эту работу и сделал бы это лучше. Но пример стоит тысячи слов:
$ curl -so - dict://dict.org/'d:uuoc:jargon' | sed -Ee '/^151/,/^[.]/!d;/^[.0-9]/s/.*//' > uuoc.txt
$ cat uuoc.txt | less
UUOC
[from the comp.unix.shell group on Usenet] Stands for Useless Use of {cat};
the reference is to the Unix command cat(1), not the feline animal. As
received wisdom on comp.unix.shell observes, ?The purpose of cat is to
concatenate (or ?catenate?) files. If it's only one file, concatenating it
with nothing at all is a waste of time, and costs you a process.?
Nevertheless one sees people doing
cat file | some_command and its args ...
instead of the equivalent and cheaper
<file some_command and its args ...
or (equivalently and more classically)
some_command and its args ... <file
[...]
В приведенном выше примере мы использовали контейнер для отображения содержимого файла uuoc.txt
с помощью команды less:
cat uuoc.txt | less
Таким образом, единственной целью команды cat
было подавать стандартный ввод команды less
с содержимым файла uuoc.txt
. Мы бы получили такое же поведение, используя перенаправление оболочки:
less < uuoc.txt
Собственно, команда,less
, как и многие команды, также принимает имя файла в качестве аргумента. Поэтому мы могли просто написать это вместо этого:
less uuoc.txt
Как вы можете видеть, здесь нет необходимости в применении команды cat
. Мы упоминаем анти-шаблон «Бесполезное использование cat», потому, что, если вы публично используете ее на форуме или в другом месте, несомненно, кто-то укажет на это с аргументом, который вы создадите «лишний процесс для ничего».
Должны признаться, что долгое время мы были довольно пренебрежительным с такими комментариями. В конце концов, на нашем современном оборудовании добавление одного дополнительного процесса для однократной операции не может вызвать слишком много накладных расходов.
Но при написании этой статьи мы сделали быстрый эксперимент, сравнивая время, требуемое с UUOC и без него тестовым скриптом awk
для обработки 500 МБ данных, поступающих с медленного носителя.
К нашему удивлению, разница была далека от незначительной.
Однако причина заключается не в создании дополнительного процесса. Но из-за дополнительного чтения/записи и переключения контекста UUOC берет на себя (как вы можете вывести его из времени, потраченного на выполнение системного кода). Поэтому, действительно, когда вы работаете с большими наборами данных, дополнительная команда cat
имеет невыгодную стоимость. Что касается нас, мы постараемся быть более бдительными с этим сейчас! А вы? Если у вас есть примеры бесполезного использования Cat, не стесняйтесь делиться ими с нами!