Grep : 매뉴얼 페이지에서 제목의 단어를 검색 할 때 예기치 않은 결과


19

macOS에서 맨 페이지를 grep하려고 할 때 이상한 동작이 발생합니다. 예를 들어, Bash 매뉴얼 페이지에는 분명히 문자열이 나타납니다 NAME.

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

그리고 내가 grep name하면 결과가 나오지만 grep하면 NAME그렇지 않습니다.

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

필자가 알고있는 다른 대문자 단어를 시도했지만 결과를 SHELL검색하는 동안 아무것도 찾지 않습니다 BASH.

무슨 일이야?

업데이트 : 모든 답변 감사합니다! 나는 이것에 부딪친 맥락을 추가 할 가치가 있다고 생각했다. 랩을 위해 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
}


어떤 운영 체제를 사용하고 있습니까? 허용 된 답변은 정확하지만 IO는 Arch Linux 상자에서이를 재현 할 수 없습니다. man bash | grep NAME예상대로 작동합니다.
terdon

@ terdon 나는 MacOS에 있습니다. Bash 3.2 및 4.4.5에서이 동작을 얻습니다
ivan

따로 : 내장을 감지하면 bash help명령을 사용하여 정보를 얻을 수 있습니다.
Joe

@Joe 문제는 종종 help결과가 너무 많이 나오는 것을 발견한다는 것입니다. 예를 들어 help completecomplete섹션 과 섹션을 확인하십시오 man bash.
ivan

답변:


33

| sed -n l해당 tail명령 에 a 를 추가하면 인쇄 할 수없는 문자를 표시 할 수 있습니다.

N\bNA\bAM\bME\bE

즉, 각 문자는 XBackspace 로 작성됩니다 X. 현대 터미널에서는 문자 가 아무런 차이없이 백 스페이스 (일명 BS BS aka \baka ^H는 커서를 한 열 왼쪽으로 이동하는 문자이므로) 자체로 덮어 씁니다 . 그러나 고대의 타자기에서는 잉크가 두 배나 많이 들어감에 따라 문자가 굵게 표시됩니다.

여전히, 호출기는 more/ less굵은 체를 의미하는 형식을 이해하므로 roff굵은 체 텍스트를 출력 하는 것은 여전히 그렇습니다 .

일부 man 구현은 roff해당 시퀀스가 ​​사용되지 않는 방식으로 호출하거나 ( 환경 변수가 설정 되지 않은 한 구현 col -b -p -x의 경우와 같이 내부적으로 시퀀스 를 제거하여 호출) 출력을 감지 할 때 호출기를 호출하지 않습니다 터미널로 가지 않고 (여기서 작동 할 것입니다), 당신의 것이 아닙니다.man-dbMAN_KEEP_FORMATTINGman 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에 전달되지 않습니다 grottygrottyANSI SGR 이스케이프 시퀀스가 사용의 기본으로 돌아갑니다).

MANCOLOR=1 man bash | grep NAME

거기에서 작동합니다.

데비안에서는 GROFF_SGR이 기본값이 아닙니다. 당신이 할 경우 :

GROFF_SGR=1 man bash | grep NAME

그러나 manstdout은 터미널이 아니기 때문에 GROFF_NO_SGR변수를 전달해야합니다 grotty( SGR 시퀀스를 제거하는 방법을 모르더라도 col -bpxBS 시퀀스를 제거하는 데 사용할 수 있다고 가정 col합니다. 그것을 수행 MAN_KEEP_FORMATTING우리의 무시한다) GROFF_SGR. 대신 할 수 있습니다 :

GROFF_SGR=1 MANPAGER='grep NAME' man bash

(터미널에서) SGR 이스케이프 시퀀스를 갖습니다.

이때 해당 NAME 중 일부가 터미널 (및 less -R호출기) 에 굵게 표시됩니다 . 출력을 sed -n l( MANPAGER='sed -n /NAME/l')에 공급하면 다음과 같은 내용이 표시됩니다.

\033[1mNAME\033[0m$

\e[1mANSI 호환 터미널에서 굵게 표시 \e[0m할 시퀀스 와 모든 SGR 속성을 기본값으로 되 돌리는 시퀀스는 어디에 있습니까 ?

해당 텍스트 grep NAME에는 해당 텍스트에 포함 된대로 작동 NAME하지만 텍스트의 일부만 굵게 / 밑줄로 표시된 텍스트를 찾는 경우 여전히 문제가 발생할 수 있습니다.


2
와우, 물리적 텔레타이프의 유산을 볼 수 있다는 것은 매우 흥미 롭습니다. 두 배의 잉크 => 굵은 체. 완벽하게 이해
ivan

1
sed -n l의 대체품으로 사랑 하고 od있습니다.
Tom Hale

13

매뉴얼 페이지를 보면 머리글이 굵게 표시되어 있습니다. 이것은 제어 문자로 형식을 지정하여 달성됩니다. 할 수 있으려면 grep당신이 원하는 것 같은,이 밖으로 제거해야합니다.

col유틸리티는 다음을 위해 사용될 수 있습니다.

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

-b옵션에는 OpenBSD에 대한 다음 설명이 있습니다 .

각 열 위치에 쓰여진 마지막 문자 만 인쇄하여 백 스페이스를 출력하지 마십시오. 이것은 mandoc (1)의 출력을 처리하는 데 유용 할 수 있습니다.


Linux col매뉴얼 (우분투)에는 마지막 문장이 없지만 (같은 방식으로 작동합니다).

Linux에서는 MAN_KEEP_FORMATTING환경 변수를 설정 해제 하거나 빈 문자열로 설정하면 도움이 될 수 grep있으며를 man통해 출력을 전달하지 않아도 됩니다 col -b.


나는 이것을 아치와 우분투 시스템에서 테스트 한 것처럼 리눅스에서 이것이 더 이상 필요하지 않다고 생각합니다. 두 시스템 모두 NAME에서 bash 매뉴얼은 just NAME, no \b입니다.
terdon

@terdon 나는 먼저 macOS에 대해 언급하지 않았으므로 잘못 구성된 Linux 시스템이 가능하다고 가정했습니다. 나는 이제 리눅스 비트를 다듬었다.
Kusalananda

당신은 아무것도 놓치지 않았다. 나는 리눅스에서 재생할 수 없기 때문에 어떤 OS를 사용하고 있는지 OP에게 물었다. 그들은 macOS를 말했고 지금 막 추가했다. 그리고 나는 당신이 틀렸다는 것을 암시하지 않았습니다. 모든 MAN_KEEP_FORMATTING변수가 당신이 말한대로 정확하게 작동하는 곳에서 Linux 배포판이 있다는 것을 알고 있기 때문 입니다. 나는 항상 그렇지는 않다는 것을 지적하고 싶었다.
terdon
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.