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
즉, 각 문자는 X
Backspace 로 작성됩니다 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 -u
grotty
-P-cbu
groff
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_SGR
grotty
-c
less
-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 -bpx
col
MAN_KEEP_FORMATTING
GROFF_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[1m
ANSI 호환 터미널에서 굵은 글꼴을 활성화하는 시퀀스와 \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
전달할 필요가 없습니다 .grep
man
col -b