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 complete의 complete섹션 과 섹션을 확인하십시오 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에 전달되지 않습니다 grotty및 grottyANSI 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.