Grep: неожиданные результаты при поиске слов в заголовке на странице руководства

Использование awk

awk '{gsub(/=/, "=\""); gsub(/,/,"\","); print $0"\""}' < file.txt
19
15.06.2017, 19:12
2 ответа

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

Для этого можно использовать утилиту col:

$ man bash | col -b | grep 'NAME'

Параметр -b имеет следующее описание в OpenBSD:

Не выводить любые символы возврата, печать только последнего символа записывается в каждую позицию столбца. Это может быть полезно в обработка вывода mandoc(1).


Linux в руководстве col (на Ubuntu) нет последнего предложения (но оно работает точно так же).

В Linux также может помочь сброс переменной среды MAN_KEEP_FORMATTING (или установка для нее пустой строки), что позволит вам grep без передачи вывода man по col -b.

13
27.01.2020, 19:44

Если добавить | sed -nl к этой команде tail для отображения непечатаемых символов вы, вероятно, увидите что-то вроде:

N\bNA\bAM\bME\bE

То есть каждый символ записывается как X Backspace X. На современных терминалах символ в конечном итоге записывается сам по себе (так как Backspace, он же BS, он же \b он же ^H — это символ, который перемещает курсор на один столбец влево) без разница. Но в древних телепишущих машинках это привело бы к тому, что символ был бы выделен жирным шрифтом, поскольку он набирал вдвое больше чернил.

Тем не менее, пейджеры типа more/less понимают, что этот формат означает выделение жирным шрифтом, поэтому roff по-прежнему выводит текст жирным шрифтом.

Некоторые реализации man будут вызывать roff так, чтобы эти последовательности не использовались (или внутренне вызывать col -b -p -x для их удаления, как в случае man-db (если не установлена ​​переменная среды MAN_KEEP_FORMATTING)), и не вызывать пейджер, когда они обнаруживают, что вывод не идет на терминал (поэтому man bash | grep NAME сработает там), но не ваш.

Вы можете использовать col -b для удаления этих последовательностей (есть и другие типы (_ BS X), а также для подчеркивания).

Для систем, использующих GNU roff (например, GNU или FreeBSD), вы можете избежать использования этих последовательностей в первую очередь, убедившись, что опции -c -b -u передается в grotty, например, убедившись, что опции -P-cbu переданы в groff.

Например, создав скрипт-оболочку с именем groff, содержащий:

#! /bin/sh -
exec /usr/bin/groff -P-cbu "$@"

Который вы помещаете перед /usr/bin/groff в $PATH.

С помощью man в macOS (также с использованием GNU roff) вы можете создать man-no-overstrike.conf с помощью:

NROFF /usr/bin/groff -mandoc -Tutf8 -P-cbu

И вызовите man как:

man -C man-no-overstrike.conf bash | grep NAME

Все еще с GNU roff, если вы установите переменную окружения GROFF_SGR (или не не устанавливает переменную GROFF_NO_SGR в зависимости от того, как были установлены значения по умолчанию во время компиляции), затем grotty (пока не передана опция -c ) будет использовать escape-последовательности терминала ANSI SGR вместо этих приемов BS для атрибутов символов. less понимают их при вызове с опцией -R.

Менеджер FreeBSD вызывает grotty с параметром -c, если только вы не запрашиваете цвета, устанавливая переменную MANCOLOR (в этом случае - c не передается в grotty, а grotty возвращается к значению по умолчанию с использованием управляющих последовательностей ANSI SGR).

MANCOLOR=1 man bash | grep NAME

будет работать там.

В Debian GROFF_SGR не используется по умолчанию. Если вы это сделаете:

GROFF_SGR=1 man bash | grep NAME

, однако, поскольку стандартный вывод man не является терминалом, он берет на себя также передачу переменной GROFF_NO_SGR в grotty (Я полагаю, что он может использовать col -bpx для удаления последовательностей BS, поскольку col не знает, как удалить последовательности SGR, хотя он все еще делает это с MAN_KEEP_FORMATTING), который переопределяет наш GROFF_SGR. Вместо этого вы можете сделать:

GROFF_SGR=1 MANPAGER='grep NAME' man bash

(в терминале), чтобы иметь escape-последовательности SGR.

На этот раз вы заметите, что некоторые из этих NAME выделены жирным шрифтом на терминале (и в пейджере less -R). Если вы передадите вывод sed -nl (MANPAGER='sed -n /NAME/l'), вы увидите что-то вроде:

\033[1mNAME\033[0m$

Где \ e[1m — это последовательность включения полужирного шрифта в терминалах, совместимых с ANSI,и \e[0m последовательность для возврата всех атрибутов SGR к значениям по умолчанию.

В этом тексте grep ИМЯ работает, так как этот текст действительно содержит ИМЯ, но у вас могут возникнуть проблемы при поиске текста, где только часть его выделена жирным шрифтом/подчеркнута.

34
27.01.2020, 19:44

Теги

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