Grep: 매뉴얼 페이지에서 제목에 있는 단어를 검색할 때 예기치 않은 결과가 발생함

Grep: 매뉴얼 페이지에서 제목에 있는 단어를 검색할 때 예기치 않은 결과가 발생함

macOS에서 매뉴얼 페이지를 검색하려고 하면 이상한 동작이 발생합니다. 예를 들어, Bash 매뉴얼 페이지에는 다음 문자열이 눈에 띄게 나타납니다 NAME.

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

grep을 수행하면 name결과를 얻을 수 있지만 grep을 수행하면 결과를 NAME얻을 수 없습니다.

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

내가 알고 있는 다른 대문자 단어를 시도해 보았으나 검색 SHELL결과가 나오지 않았습니다 BASH.

여기서 무슨 일이 일어나고 있는 걸까요?

고쳐 쓰다: 모든 답변에 감사드립니다! 이 문제가 발생한 이유에 대한 배경을 추가하는 것이 가치가 있다고 생각했습니다. 나는 Wrap 에 대한 bash 함수를 작성하고 싶고 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
}

답변1

인쇄할 수 없는 문자를 표시하기 위해 명령 | sed -n l에 a를 추가 하면 다음과 같은 내용이 표시될 수 있습니다.tail

N\bNA\bAM\bME\bE

즉, 각 문자는 XBackspace 로 작성됩니다 X. 최신 터미널에서는 문자 자체를 덮어쓰게 되므로(백스페이스(BS라고도 함)는 커서를 한 열 왼쪽으로 이동하는 문자이기 \b때문에 ) 아무런 차이가 없습니다. ^H그러나 고대 텔레타이프에서는 잉크 양이 두 배이므로 문자가 굵게 표시됩니다.

그럼에도 불구하고 more/와 같은 호출기는 less형식이 굵게 표시된다는 것을 이해하므로 이것이 여전히 roff굵은 텍스트를 출력하는 방법입니다.

일부 구현에서는 roff이러한 시퀀스를 사용하지 않는 방식으로 이를 호출하고(또는 구현의 경우와 col -b -p -x같이 이를 제거하기 위해 내부적으로 호출함 man-db( MAN_KEEP_FORMATTING환경 변수가 설정되지 않은 경우)) 출력이 다음과 같을 때 호출기를 호출하지 않습니다. 감지되어 터미널로 이동하지 않지만(그래서 man bash | grep NAME그곳에서 작업해도 괜찮습니다) 귀하의 터미널로는 이동하지 않습니다.

를 사용하여 이러한 시퀀스(다른 유형( BS ) 및 밑줄도 col -b있음)을 제거 할 수 있습니다 ._X

GNU(예: GNU 또는 FreeBSD)를 사용하는 시스템의 경우 roff옵션이 에 전달되는지 확인하여 처음부터 이러한 시퀀스를 사용하지 않을 수 있습니다.-c -b -ugrotty-P-cbugroff

groff예를 들어 "include"라는 래퍼 스크립트를 생성하면 다음과 같습니다 .

#! /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) (옵션이 전달되지 않는 한) ANSI SGR 터미널 이스케이프 시퀀스가 ​​사용됩니다. . 역할 속성에 대한 넌센스입니다. 옵션을 호출할 때 이를 이해하십시오.GROFF_NO_SGRgrotty-cless-R

FreeBSD의 사람은 당신이 요청하지 않는 한 grotty이 옵션을 호출 할 것입니다-c색상MANCOLOR 변수를 설정합니다(이 경우 ANSI SGR 이스케이프 시퀀스를 사용하여 -c전달되지 않고 grotty기본값 grotty으로 되돌아갑니다).

MANCOLOR=1 man bash | grep NAME

거기에서 일할 것입니다.

데비안에서는 GROFF_SGR이 기본값이 아닙니다. 이렇게 하면:

GROFF_SGR=1 man bash | grep NAME

그러나 man의 stdout은 터미널이 아니며 자체적으로 변수를 전달하기 GROFF_NO_SGR때문에 ( 아직 실행 중이더라도 SGR 시퀀스를 제거하는 방법을 모르기 때문에 BS 시퀀스를 제거 grotty하는 데 사용할 수 있을 것 같습니다 ) 덮어쓰게 됩니다. 우리의 .col -bpxcolMAN_KEEP_FORMATTINGGROFF_SGR

GROFF_SGR=1 MANPAGER='grep NAME' man bash

(터미널에서) SGR 이스케이프 시퀀스를 가져옵니다.

그 시점에서 다음 중 일부를 발견하게 될 것입니다.이름s는 터미널(및 호출기)에 굵은 글씨로 표시됩니다 less -R. 출력을 sed -n l( ) 에 입력하면 MANPAGER='sed -n /NAME/l'다음과 같은 내용이 표시됩니다.

\033[1mNAME\033[0m$

그 중에는 \e[1mANSI 호환 터미널에서 굵은 글꼴을 활성화하는 시퀀스와 \e[0m모든 SGR 속성을 기본값으로 복원하는 시퀀스가 ​​있습니다.

이것이 grep NAME작동하는 방식은 텍스트에 해당 내용이 포함되어 있다는 것입니다 NAME. 하지만 텍스트의 일부만 굵게/밑줄 친 텍스트를 찾으면 여전히 문제가 발생할 수 있습니다.

답변2

맨 페이지를 보면 제목이 굵게 표시된 것을 알 수 있습니다. 이는 제어 문자를 사용하여 형식을 지정함으로써 수행됩니다. 당신이 원하는 것을 좋아하려면 grep이것들을 제거해야 합니다.

col유틸리티는 다음과 같은 목적으로 사용될 수 있습니다.

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

-b옵션에는 다음과 같은 설명이 있습니다.OpenBSD에서:

백스페이스는 출력되지 않으며 각 열 위치에 쓰여진 마지막 문자만 인쇄됩니다. 이는 mandoc(1)의 출력을 처리하는 데 유용합니다.


Linux col매뉴얼(Ubuntu)에는 마지막 문장이 없습니다(그러나 동일한 방식으로 작동합니다).

Linux에서는 환경 변수를 설정 해제 하거나 빈 문자열로 설정하는 것도 도움이 될 수 있으며 출력을 MAN_KEEP_FORMATTING전달할 필요가 없습니다 .grepmancol -b

관련 정보