Grep: несподівані результати під час пошуку слів у заголовку зі сторінки man


19

Я стикаюся з дивною поведінкою, намагаючись зірвати сторінку чоловіка на macOS. Наприклад, на сторінці "Bash man" явно є рядок NAME:

$ man bash | head -5 | tail -1
NAME

І якщо я грепну за, nameя отримую результати, але якщо я грепну, NAMEя не:

$ man bash | grep 'NAME'
$ man bash | grep NAME

Я спробував інші великі слова, за якими я знаю, що там є, і SHELLнічого не шукаю, тоді як пошук BASHрезультатів.

Що тут відбувається?

Оновлення : Дякую за всі відповіді! Я вважав, що варто додати контекст, в якому я натрапив на це. Мені хотілося написати функцію bash для завершення, manі у випадках, коли я намагався шукати підручну сторінку для вбудованої оболонки, перейдіть до відповідного розділу сторінки Man Bash. Може бути і кращий спосіб, але ось що я зараз маю:

man () {
  case "$(type -t "$1")" in
    builtin)
      local pattern="^ *$1"

      if bashdoc_match "$pattern \+[-[]"; then
        command man bash | less --pattern="$pattern +[-[]"
      elif bashdoc_match "$pattern\b"; then
        command man bash | less --pattern="$pattern[[:>:]]"
      else
        command man bash
      fi
      ;;
    keyword)
      command man bash | less --hilite-search --pattern='^SHELL GRAMMAR$'
      ;;
    *)
      command man "$@"
      ;;
  esac
}

bashdoc_match() {
  command man bash | col -b | grep -l "$1" > /dev/null
}


Яку операційну систему ви використовуєте? Я впевнений, що прийнята відповідь правильна, але IO не міг відтворити це у вікні Arch Linux. man bash | grep NAMEпрацює як очікувалося.
тердон

@terdon Я на macOS. Таку поведінку я розумію з Bash 3.2 та 4.4.5
ivan

Як і в сторону: якщо ви виявите вбудований, ви можете просто скористатися командою bash, helpщоб отримати його інформацію.
Джо

@Joe Проблема в тому, що я часто вважаю, що helpрезультати залишають занадто багато. Наприклад , help completeознайомтеся з completeрозділом man bash.
ivan

Відповіді:


33

Якщо ви додасте | sed -n lдо цієї tailкоманди, щоб показати символи, що не друкуються, ви, ймовірно, побачите щось на зразок:

N\bNA\bAM\bME\bE

Тобто кожен символ пишеться як XBackspace X. На сучасних терміналах символ в кінцевому підсумку пишеться над собою (як Backspace aka BS aka \baka ^H- символ, який переміщує курсор на один стовпець ліворуч) без різниці. Але в стародавніх машинках-машинках це може призвести до того, що персонаж з'являється жирним шрифтом, оскільки він отримує вдвічі більше чорнила.

Тим не менш, пейджери на зразок more/ lessдій розуміють, що цей формат означає жирний, так що це все ще roffозначає, що виводити жирний текст.

Деякі реалізовані люди закликають 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.

За допомогою macOS ' man(також використовуючи 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опція) замість цього використовуватиметься послідовність аварійних терміналів 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

однак, оскільки manstdout 's не є терміналом, він бере на себе також передачу GROFF_NO_SGRзмінної grotty(я вважаю, що вона може використовувати col -bpxдля зчитування послідовностей BS, оскільки colне знає, як знімати послідовності SGR, хоча вона все ще є робить це з MAN_KEEP_FORMATTING), що перекриває наше GROFF_SGR. Ви можете зробити замість цього:

GROFF_SGR=1 MANPAGER='grep NAME' man bash

(у терміналі), щоб мати послідовності втечі SGR.

Цього разу ви помітите, що деякі з цих імен з’являються жирним шрифтом на терміналі (і в less -Rпейджері). Якщо ви подаєте вихід на sed -n l( MANPAGER='sed -n /NAME/l'), ви побачите щось на кшталт:

\033[1mNAME\033[0m$

Де \e[1mпослідовність включення жирних в ANSI-сумісних терміналів, і \e[0mпослідовність для повернення всіх атрибутів SGR до стандартних.

Цей текст grep NAMEпрацює так, як цей текст містить NAME, але у вас все ще можуть виникнути проблеми, якщо шукати текст, де лише його частини виділено жирним шрифтом / підкреслюють ...


2
Нічого собі, цікаво побачити спадщину фізичного теле-типу там. Вдвічі більше чорнила => жирним шрифтом. Має ідеальний сенс
ivan

1
Я люблю sed -n lяк заміну od.
Том Хейл

13

Якщо ви подивитеся на будь-яку сторінку керівництва, ви помітите, що заголовки виділені жирним шрифтом. Це досягається шляхом їх форматування за допомогою контрольних символів. Щоб мати можливість grepсподобатися, чого ви хочете, їх потрібно викреслити.

colУтиліта може використовуватися для цього:

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

-bВаріант має наступний опис на OpenBSD :

Не виводити ніяких зворотних просторів, друкуючи лише останній символ, записаний у кожну позицію стовпця. Це може бути корисно при обробці виводу mandoc (1).


У colпосібнику Linux (на Ubuntu) немає останнього речення там (але воно працює так само).

У Linux MAN_KEEP_FORMATTINGтакож може допомогти скидання змінної середовища (або встановлення її на порожню рядок) і дозволить вам grepне пропускати результат manчерез col -b.


Я думаю (як я тестував це в системі Arch і Ubuntu), що в Linux це вже не потрібно, або більше немає. В обох системах NAMEв посібнику з bash просто NAMEнемає \b.
terdon

@terdon Я спочатку не помітив згадування про macOS, тому припустив, що неправильно налаштована система Linux була можливою. Тепер я обрізав біти Linux.
Kusalananda

Ви нічого не пропустили, я запитав ОП, яку ОС вони використовують, тому що я не міг відтворити на Linux, вони сказали macOS, і я просто додав це зараз. І я не мав на увазі, що ви помилялися, бо MAN_KEEP_FORMATTING, наскільки я знаю, є дистрибутиви Linux там, де ця змінна працює саме так, як ви говорите. Я просто хотів зазначити, що це не завжди так.
terdon
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.