Как скопировать многостраничный текст из терминала в буфер обмена?

sed не подходит для этой задачи

… но это не значит, что вы не можете злоупотреблять им, чтобы выполнять свои торги:

sed -n -e "2,$ p" -e "/^~keyword~./ {s/$/§/;p}" in.txt | sed -n '/^~keyword~./,/^~[[:alpha:]]./ {/^~keyword~..*§$/ {s/§$//; b print}; /^~[[:alpha:]]./b; :print p}'

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

Чего мы хотим достичь?
Извлекаем «блоки» из файла, где каждый «блок» начинается со строки, соответствующей регулярному выражению R1 («начальные строки»), и заканчивается строкой, предшествующей следующему появлению регулярного выражения R2 («завершающие строки»).

Так что просто используйте диапазоны шаблонов sed , в чем проблема?
R2 - это подмножество R1, поэтому наши «линии-ограничители» могут быть началом новых блоков. sed не поддерживает перекрывающиеся блоки.

Итак, создайте регулярное выражение, которое соответствует R2, но не соответствует R1.
Для этого потребуются утверждения нулевой длины, которых нет в sed . (Помните, как я сказал, что sed не был подходящим инструментом для этого?)

Решение: если поиск «линии терминатора» поглощает «начальные строки», просто продублируйте «начальные строки» .
Это сработает, но мы не должны дублировать первую «начальную строку», иначе мы просто увидим каждую повторяющуюся пару как блок. 1

sed -n -e "2,$ p" -e "/^~keyword~./ {s/$/§/;p}" in.txt

= Распечатать все строки, начинающиеся со строки номер 2 (т.е. все, кроме строки 1). Также выведите строки второй раз , если они соответствуют R1. Я перейду к s / $ / § / чуть позже.

Теперь, когда у нас есть четко разделенные блоки, используйте диапазон шаблонов для печати всех строк, заключенных между началом блока и признаками конца: sed -n '/^~keyword~./,/^~[[:alpha :]] ./ p '

Ой, подождите, это включает в себя линии терминатора. Stack Overflow спешит на помощь .
Но мы не можем просто пропустить все строки, соответствующие R2 - помните, что R1 ⊂ R2, поэтому удаление строк-терминаторов приведет к удалению и начальных строк.

«К счастью», sed имеет ветвление.Как насчет того, чтобы напечатать все, что соответствует R1, и отбросить только совпадения для R2 , затем ?

sed -n '/^~keyword~./,/^~[[:alpha:]]./ {/^~keyword~./b print; /^~[[:alpha:]]./b; :print p}'

Отлично, теперь мы печатаем наши дублированные начальные строки, когда они оказываются строкой-ограничителем ... Если бы только там было способ отличить исходные начальные строки от их дубликатов…

Вот почему у нас было s / $ / § / : добавить § в конце каждого дублированного начала строка (обратите внимание, что дублированные §'ы дублированные начальные строки в конечном итоге будут теми, которые начинают блок, а не-§'Ed начальные строки будут теми, которые ограничивают блоки, за которыми сразу же следует другой блок).

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

Для всех строк в диапазоне блоков…

  • Проверить, соответствует ли строка R1 и имеет ли она завершающий §.
    Если это так, удалите § и перейдите к печати строки.
  • В противном случае (т.е. если мы не прыгнули) удалите все строки, соответствующие R2, пропустив все дальнейшие команды (включая печать).
  • Наконец, напечатайте текущую строку.
{/^~keyword~..*§$/ {s/§$//; b print}; /^~[[:alpha:]]./b; :print p}

Конечный результат:

sed -n -e "2,$ p" -e "/^~keyword~./ {s/$/§/;p}" in.txt | sed -n '/^~keyword~./,/^~[[:alpha:]]./ {/^~keyword~..*§$/ {s/§$//; b print}; /^~[[:alpha:]]./b; :print p}'

Однако это предполагает, что первая начальная строка файла (соответствующая R1) находится в строке 1 (помните, что это единственная строка, которую мы исключили при дублировании начальных строк). В противном случае вы получите аккуратные пары, но не данные:

~keyword~, ~output~.
~keyword~, ~output~.

Возможно, вы могли бы добавить больше сопоставлений и ветвлений, чтобы обойти это, но на самом деле…

просто используйте awk .

15
19.01.2014, 18:03
6 ответов

У меня есть пара несовершенных, но, возможно, полезных идей.

Способ 1 - мышонок.

Используйте полосу прокрутки терминала.

Подробности (при условии xterm ; для других терминалов потребуются настройки.)

  1. Включите полосу прокрутки, если это еще не сделано. (В xterm он находится в меню, которое вы получаете с помощью Ctrl + Button2.)
  2. Убедитесь, что less не работает с параметром -c (I включили эту опцию в моей переменной окружения LESS , но она мешает тому, что мы собираемся делать, поэтому мне нужно ввести -c , чтобы выключить ее.)
  3. Используя любые команды less , которые вам нравятся, прокрутите вверх или вниз, чтобы первая строка, которую вы хотите скопировать, была видна на экране.
  4. Triple-Button1 выбранная вами стартовая линия, чтобы выбрать ее.
  5. Прокрутите вниз, пока на экране не появится последняя строка, которую вы хотите скопировать. Вы должны использовать только пробел или другие простые клавиши прокрутки, а не поиск / - суть здесь в том, чтобы получить на меньше для отправки всех строк на терминал, чтобы их можно было скопировать .
  6. Button3 на выбранной вами конечной линии, чтобы расширить выбор.

Возможная трудность: ваш буфер обратной прокрутки может быть недостаточно большим.Это можно изменить в xterm с помощью ресурса saveLines или параметра командной строки -sl , но я не знаю способа изменить его в xterm это уже работает.

Метод 2 - немышь.

Используйте команду | (вертикальная черта) в less , чтобы отправить текст в xclip .

Подробности:

  1. Используя любые команды less , которые вам нравятся, прокрутите вверх или вниз, чтобы поместить последнюю строку, которую вы хотите скопировать, вверху экрана. Вы можете пропустить этот шаг и следующий шаг, если хотите скопировать до конца.
  2. Используйте команду m (отметка), чтобы установить отметку в выбранной конечной позиции. Метки сами по себе являются полезной функцией, и вы должны знать их уже из vi , но на всякий случай вы этого не сделаете: m x устанавливает метку, где x может быть любой буквой, а ' x вернет вас туда позже.
  3. Теперь прокрутите вверх, чтобы первая строка, которую вы хотите скопировать, оказалась в верхней части экрана.
  4. Используйте команду конвейера: | x , которая вызовет приглашение для ввода внешней команды. x должно быть той же буквой отметки, которую вы использовали в команде m , или $ для «до конца». Введите там xclip .

Простой случай копирования всей страницы руководства сводится к g | $ x c l i p Enter .

Предупреждение (т. Е. ужасная вещь, которая только что произошла со мной ): xclip будет полу-фоновым, запущенным как часть группы процессов less . Если вы попытаетесь приостановить меньше , запустить другое задание на том же терминале и вставить в него данные, это не сработает. Затем, когда вы позже поставите на передний план задание man / less , паста внезапно выйдет наружу. Я думаю, это следует рассматривать как ошибку xclip ...

10
29.04.2021, 00:43

Как указано на Nixcraft :

  1. Получить xclip :

     sudo apt-get install xclip 
     

    или

     yum install xclip 
     

    в системе на основе RPM.

  2. человек мужчина | your_magic_here | xclip -selection clipboard
  3. Ctrl + V сколько душе угодно. Вы можете удалить -выборный буфер обмена , чтобы вместо этого выбрать вставку средним щелчком мыши (так называемый первичный выбор).

Обратите внимание, что your_magic_here - это заполнитель для текстового фильтра ( sed / awk / perl / ...), который выбирает желаемую часть справочной страницы в соответствии с вашим конкретным вариантом использования, который вы не описали, поэтому, боюсь, я не могу привести конкретный пример.

2
29.04.2021, 00:43

Терминальный мультиплексор, такой как tmux или screen , обычно имеет подобную функциональность (то есть, чтобы сохранить часть буфера прокрутки в файл или передать его какой-либо команде), и их использование обычно в любом случае хорошая идея, так что вы можете взглянуть на один из них.

2
29.04.2021, 00:43

Предполагая, что вы используете gnome-terminal и less в качестве пейджера для man вы можете:

  • Запустить less для man с помощью клавиши -X , чтобы отключить альтернативный экран, например: LESS = - X man less

Это позволит добавить вывод man в буфер истории эмулятора терминала. Подробнее см. В этом ответе https://unix.stackexchange.com/a/38638/87918 .

  • Прокрутите до последней страницы текста, который хотите скопировать.(Весь прокрученный текст будет сохранен в буфере истории при прокрутке)
  • Выделите текст мышью в gnome-terminal , начиная с последней страницы до первой, перетащив мышь к верхнему краю окна. Подробный процесс выделения текста описан здесь :

Это не работает в Gnome Terminal. Вместо этого вам нужно начать выделение левой кнопкой мыши и, делая это, перетащить курсор мыши к краю окна (или за пределы окна ). G-T будет прокручивать элементы за вас, расширяя выбор в процессе. Прокрутка G-T выполняется достаточно быстро, поэтому это достаточно удобный и интуитивно понятный процесс, возможно, лучше, чем у xterm.

  • Теперь у вас есть выделенный текст (любые страницы, которые вы хотите), который вы можете копировать и вставлять где угодно.
0
29.04.2021, 00:43

Это зависит от вашей терминальной программы, но большинство терминальных программ не имеют функции сохранения выделенного текста.

LXTerminal, uxterm, Konsole и GNOME Terminal, кажется, лишены этой "функции", но могут быть и другие, у которых она есть. Посмотрите на структуру меню вашей терминальной программы, возможно, там есть что-то вроде "Сохранить выделенное"

0
29.04.2021, 00:43

Используйте | (pipe )команда в меньшем количестве с метками, как ответил Wumpus Q. Wumbley в его втором варианте , но перенаправление с использованием tee для добавления к уже существующему файлу для этой цели:

|tee >> ~/helpaggregator.txt

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

2
29.04.2021, 00:43

Теги

Похожие вопросы