С тем, кто считает, что обладает истиной, и не ищет ее, спорить невозможно (Р. Роллан).

7 практических примеров использования команды paste в Linux

1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (1 оценок, среднее: 5,00 из 5)
Загрузка...

Статья опубликована: 29 июля 2018

7 практических примеров использования команды paste в Linux
Команда paste объединяет несколько входных файлов для создания из них нового текстового файла с разделителями. Мы рассмотрим, как эффективно использовать команду paste в Linux и Unix.

7 практических примеров использования команды paste в Linux

Содержание:

1. Вставка столбцов

В самом основном случае использования команда paste принимает N входных файлов и присоединяется к ним по строкам на выходе:

 

Но давайте теперь дадим теоретические объяснения для практического примера. Если вы загрузили образцы файлов, вы увидите, что у нас есть несколько файлов данных, соответствующих различным столбцам таблицы:

 

Из этих данных довольно легко создать текстовый файл с разделителями табуляции:

 

Как вы можете видеть, при отображении на консоли содержимое этого файла с разделителями разделов не создает идеально отформатированную таблицу. Но это по дизайну: команда paste не используется для создания текстовых файлов с фиксированной шириной, а только текстовые файлы с разделителями, где одному заданному символу назначается роль разделителя полей.

Таким образом, даже если это не очевидно в выводе выше, на самом деле между каждым полем есть один и только один символ табуляции. Давайте сделаем это с помощью команды sed :

 

Теперь невидимые символы отображаются однозначно на выходе. И вы можете видеть символы табуляции, отображаемые как \t. Вы можете их подсчитать: на каждой выходной строке всегда есть три вкладки – одна между каждым полем. И когда вы видите два из них подряд, это означает, что там было пустое поле. Это часто бывает в файлах наших конкретных примеров, поскольку в каждой строке задано либо поле CREDIT, либо DEBIT, но оба они одновременно.

2. Изменение разделителя полей

Как мы видели, команда paste использует символ табуляции в качестве разделителя полей по умолчанию («разделитель»). Что-то, что мы можем изменить, используя эту опцию -d. Предположим, я хотел бы вместо этого использовать полуточку:

 

Нет необходимости добавлять команду sed в конце конвейера здесь, так как разделитель, который мы использовали, является печатным символом. Во всяком случае, результат тот же: в данной строке каждое поле отделяется от своего соседа с помощью односимвольного разделителя.

3. Транспонирование данных с использованием последовательного режима

В приведенных выше примерах есть одна общая черта: команда paste считывает все свои входные файлы параллельно, что требуется, поэтому она может объединять их по очереди на выходе.

Но команда paste также может работать в так называемом последовательном режиме, с использованием флага -s. Как следует из названия, в последовательном режиме команда paste будет считывать входные файлы один за другим. Содержимое первого входного файла будет использоваться для создания первой выходной строки. Затем содержимое второго входного файла будет использоваться для создания второй выходной строки и т. д. Это также означает, что на выходе будет столько строк, сколько файлов на входе.

Более формально данные, взятые из файла N, будут отображаться в виде N-й строки на выходе в последовательном режиме, тогда как он будет отображаться как N-й столбец в режиме «параллельного» по умолчанию. В математических терминах таблица, полученная в последовательном режиме, представляет собой транспонирование таблицы, созданной в режиме по умолчанию (и наоборот).

Чтобы проиллюстрировать это, рассмотрим небольшую подвыборку наших данных:

 

В режиме по умолчанию («параллельный») данные входного файла будут выступать в качестве столбцов на выходе, создавая таблицу из двух столбцов на пять строк:

 

Но в последовательном режиме данные входного файла будут отображаться в виде строк, создавая теперь таблицу из пяти столбцов на две строки:

4. Работа со стандартным вводом

Как и многие стандартные утилиты, команда paste может использовать стандартный ввод для чтения данных. Либо неявно, когда нет имени файла, заданного в качестве аргумента, либо явно с помощью специального имени файла. По-видимому, это не так полезно:

 

Мы рекомендуем вам протестировать его самостоятельно, но следующий синтаксис должен приводить к тому же результату, что и команда paste в этом случае бесполезна:

 

Итак, какова может быть точка чтения данных со стандартного ввода? Ну, с флагом -s, все становится намного интереснее, как мы это увидим сейчас.

4.1. Объединение строк файла

Как мы видели в параграфах ранее, в последовательном режиме команда paste будет записывать все строки входного файла на той же выходной строке. Это дает нам простой способ объединить все строки, считанные со стандартного ввода, только в одну (потенциально очень длинную) выходную строку:

 

Это в основном то же самое, что вы могли бы сделать с помощью команды tr, но с одной разницей. Давайте используем утилиту diff, чтобы определить:

 

Как сообщается утилитой diff, мы можем видеть, что команда tr заменила каждый экземпляр символа новой строки на данный разделитель, в том числе самый последний. С другой стороны, команда paste сохранила последний символ новой строки без изменений. Так что, если вам нужен разделитель после самого последнего поля или нет, вы будете использовать одну команду или другую.

4.2. Многостолбцовое форматирование одного входного файла

Согласно спецификации Open Group, «стандартный ввод должен читать одну строку за один раз» с помощью команды paste. Таким образом, передача нескольких вхождений имени -специального файла в качестве аргументов в команду paste приведет к тому, что несколько последовательных строк ввода будут записаны в одну и ту же выходную строку:

 

Чтобы сделать все более ясным, мы рекомендуем вам изучить разницу между двумя приведенными ниже командами. В первом случае команда paste открывает три раза один и тот же файл, что приводит к дублированию данных на выходе. С другой стороны, во втором случае файл ACCOUNTLIB открывается только один раз (оболочкой), но три раза считывается для каждой строки (по команде paste), в результате чего содержимое файла отображается в виде трех столбцов:

 

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

5. Работа с файлами разной длины

Спецификации Open Group для утилиты paste достаточно ясны:

Если условие конца файла обнаружено в одном или нескольких входных файлах, но не во всех входных файлах, вставка должна вести себя так, как если бы пустые строки были прочитаны из файлов, на которых был обнаружен конец файла, если только установлен параметр -s.

Итак, поведение – это то, что вы можете ожидать: недостающие данные заменяются «пустым» контентом. Чтобы проиллюстрировать это поведение, давайте запишем еще пару транзакций в нашу «базу данных». Чтобы сохранить исходные файлы неповрежденными, мы будем работать над копией наших данных:

 

С этими обновлениями мы теперь зарегистрировали новое движение капитала со счета № 1080 на счет № 4356. Однако, как вы, возможно, заметили, я не стал обновлять файл ACCOUNTLIB. Это не кажется такой большой проблемой, потому что команда paste заменит недостающие строки пустыми данными:

 

Но будьте осторожны, команда paste может соответствовать линиям только по их физическому положению: все, что он может сказать, это файл «короче», чем другой. Не там, где данные отсутствуют. Поэтому он всегда добавляет поля пробелов в конце вывода, что может привести к неожиданным смещениям в ваших данных. Давайте сделаем это очевидным, добавив еще одну транзакцию:

 

На этот раз я был более строгим, так как я правильно обновил номер учетной записи (ACCOUNTNUM) и соответствующий ярлык (ACCOUNTLIB), а также файлы данных CREDIT и DEBIT. Но поскольку в предыдущей записи отсутствовали данные, команда paste больше не может сохранять связанные поля в одной строке:

 

Как вы можете видеть, учетная запись № 4356 сообщается с надписью «WEB HOSTING», тогда как в действительности последняя должна появиться в строке, соответствующей учетной записи № 3465.

В заключение, если вам приходится иметь дело с отсутствующими данными, вместо команды paste вы должны использовать эту joinутилиту, так как последняя будет соответствовать строкам на основе их содержимого, а не на основе позиции во входном файле. Это делает его гораздо более подходящим для приложений типа «база данных». Я уже опубликовал видео о команде join, но это, вероятно, заслуживает отдельной статьи, поэтому дайте нам знать, если вас интересует эта тема!

6. Задействовать разделители

В подавляющем большинстве случаев использования вы укажете только один символ в качестве разделителя. Это то, что мы сделали до сих пор. Однако, если вы укажете несколько символов после опции -d, команда paste будет циклически перебирать их: первый символ будет использоваться как первый разделитель поля в строке, второй символ – второй разделитель полей и т. д.

 

Разделители полей могут появляться только между полями. Не в конце строки. И вы не можете вставить более одного разделителя между двумя заданными полями. В качестве трюка для преодоления этих ограничений вы можете использовать /dev/null специальный файл в качестве дополнительного ввода, где вам нужен дополнительный разделитель:

 

Вы можете даже злоупотреблять:

 

Однако нет необходимости говорить, что если вы достигнете такого уровня сложности, это может быть ключом к тому, что pasteутилита не обязательно является лучшим инструментом для работы. Возможно, стоит подумать, в таком случае, что-то вроде команды awksed или awk.

Но что, если в списке содержится меньше разделителей, чем нужно для отображения строки на выходе? Интересно, что команда paste будет «зацикливаться» над ними. Итак, как только список исчерпан, команда paste вернется к первому разделителю, что, вероятно, откроет дверь для какого-то творческого использования. Что касается меня, я не смог сделать что-то действительно полезное с этой функцией, учитывая мои данные. Поэтому вам нужно будет удовлетвориться следующим немного надуманным примером. Но это не будет полной потерей вашего времени, так как это был хороший повод упомянуть, что вам нужно удвоить обратную косую черту (\\), когда вы хотите использовать ее как разделитель:

7. Многобайтовые разделители символов

Как и большинство стандартных утилит Unix, команда paste родилась за один символ, эквивалентный одному байту. Но это уже не так: сегодня многие системы используют кодировку переменной длины UTF-8 по умолчанию. В UTF-8 символ может быть представлен 1, 2, 3 или 4 байтами. Это позволяет нам смешивать в том же текстовом файле все разнообразие человеческой записи, а также множество символов и эмоций – при сохранении совместимости по возрастанию с унаследованной однобайтовой кодировкой символов US-ASCII.

Скажем, например, мы хотели бы использовать WHITE DIAMOND (◇ U + 25C7) в качестве нашего разделителя полей. В UTF-8 этот символ кодируется с использованием трех байтов e2 97 87. Этот символ может быть трудно получить с клавиатуры, поэтому, если вы хотите попробовать это самостоятельно, мы предлагаем вам скопировать его в блок кода ниже:

 

Довольно обманчиво, не так ли? Вместо ожидаемого белого бриллианта у нас есть символ «знак вопроса» (по крайней мере, так оно отображается в нашей системе). Однако это не «случайный» символ. Это символ замены Unicode, используемый «для указания проблем, когда система не может отобразить поток данных в правильный символ». Итак, что пошло не так?

Еще раз, изучение исходного двоичного содержимого вывода даст нам несколько подсказок:

 

У нас уже была возможность потренироваться с шестнадцатеричными дампами выше, поэтому ваши глаза теперь должны быть нацелены на то, чтобы определить полевые разделители в потоке байтов. Если посмотреть внимательно, вы увидите разделитель полей после того, как номер строки будет байтом e2. Но если вы продолжите свои исследования, вы заметите, что второй разделитель полей 97. Не только команда paste не выводила символ, который мы хотели, но он также не использовал везде тот же байт, что и разделитель?!?

Подождите минуту: разве это не напоминает вам то, о чем мы уже говорим? И эти два байта e2 97, разве они вам не знакомы? Ну, знакомый, вероятно, немного слишком много, но если вы отскакиваете несколько абзацев, вы можете найти их где-то где-то…

Так вы нашли, где это было? Ранее мы сказали, сто белый бриллиант кодируется в UTF-8 как три байта e2 97 87. И действительно, команда paste рассматривала эту последовательность не как целый трехбайтовый символ, а как три независимых байта, и поэтому он использовал первый байт в качестве первого разделителя полей, затем второй байт в качестве второго разделителя полей.

Мы позволим вам повторить этот эксперимент, добавив еще один столбец во входные данные; вы должны увидеть третий разделитель полей 87- третий байт представления UTF-8 для белого алмаза.

Хорошо, это объяснение: команда paste принимает только однобайтовые «символы» в качестве разделителя. И это особенно раздражает, так как еще раз мы не знаем, как преодолеть это ограничение, кроме как с помощью трюка /dev/null, который мы уже дали вам:

 

В настоящее время утилита игнорирует многобайтовые символы в списке разделителей и допускает однобайтовые разделители. Но мы не будем утверждать, что тестировал это для всего разнообразия платформ * nix. Поэтому, если мы что-то пропустим, не стесняйтесь использовать раздел комментариев, чтобы исправить нас!

Бонусный совет: избегайте ловушки \0

По историческим причинам:

Команды:

paste -d “\ 0″… paste -d “”…

не обязательно эквивалентны; последний не указан этим томом IEEE Std 1003.1-2001 и может привести к ошибке. Конструкция «\0» используется для обозначения «без разделителя», поскольку исторические версии past не соответствовали синтаксическим рекомендациям и команде:

paste -d “”…

getopt () не может быть обработан должным образом.

Таким образом, переносимый способ вставки файлов без использования разделителя – это указать разделитель \0. Это несколько противоречит здравому смыслу, поскольку для многих команд, \0 означает символ NUL -a символ, закодированный как байты из одних нулей, которые не должно конфликтовать с любым текстовым содержанием.

Вы можете найти символ NUL полезным разделителем, особенно когда ваши данные могут содержать произвольные символы (например, при работе с именами файлов или данными, предоставленными пользователем). К сожалению, мы не знаем, как использовать символ NUL в качестве разделителя полей с помощью команды paste. Но, может быть, вы знаете, как это сделать? Если это так, мы хотели бы прочитать ваше решение в разделе команд.

С другой стороны, pasteчасть реализации GNU Coreutils имеет нестандартную -zопцию для перехода от новой строки к символу NUL для разделителя строк. Но в этом случае символ NUL будет использоваться как разделитель строк как для ввода, так и для вывода. Итак, чтобы проверить эту функцию, нам нужна первая версия наших входных файлов с нулевым завершением:

 

Чтобы узнать, что изменилось в процессе, мы можем использовать эту утилиту hexdump для изучения исходного двоичного содержимого файлов:

 

Мы дам вам сравнить два гексагональных дампа, чтобы определить разницу между «.zero» файлами и исходными текстовыми файлами. В качестве подсказки я могу сказать, что новая строка кодируется как 0a байт.

Надеемся, вы нашли время, необходимое для поиска символа NUL в входных файлах «.zero». Во всяком случае, у нас есть версия входных файлов с нулевым завершением, поэтому мы можем использовать -zопцию pasteкоманды для обработки этих данных, создавая на выходе и результат с нулевым завершением:

 

Поскольку мои входные файлы не содержат встроенных строк в данных, этот -zпараметр имеет ограниченную полезность здесь. Но на основе приведенных выше объяснений я позволяю вам понять, почему следующий пример работает «как ожидалось». Чтобы полностью понять, что вам, вероятно, нужно загрузить образцы файлов и изучить их на уровне байта, используя hexdumpутилиту, как мы это делали выше:

Что еще?

Команда paste выводит только выделенный текст. Но, если ваша система поддерживает BSD- утилиту column, вы можете использовать ее для получения красиво отформатированных таблиц путем преобразования pasteвывода команды в текстовый формат с фиксированной шириной. Но это будет предметом предстоящей статьи. Так что следите за обновлениями и, как всегда, не забудьте поделиться этой статьей на своих любимых сайтах и в социальных сетях!

7 практических примеров использования команды paste в Linux


Читайте также

    Добавить комментарий

    Войти с помощью: 

    Ваш e-mail не будет опубликован. Обязательные поля помечены *

    Заполните форму и наш менеджер перезвонит Вам в самое ближайшее время!

    badge
    Обратный звонок 1
    Отправить
    galka

    Спасибо! Ваша заявка принята

    close
    galka

    Спасибо! Ваша заявка принята

    close