最小的例子:
man git | cat
真实例子:
man git | grep --color=always -C 3 "pathspec"
FWIW,我尝试过--pager="cat"
使用各种寻呼机,以及通过管道连接到各种寻呼机。我也尝试过使用vimcat
相同的,但不幸的是它冻结了。我什至尝试过使用unbuffered
.一切都无济于事。
也许可以使用-T
or {g,n,t}roff
,但我不确定如何?有没有办法可以通过管道传输到less
/ vim
/etc 并将其传递到 stdout带格式(颜色/等)和不分页?
编辑:感谢下面 Stéphane 的帮助,我现在有了一种轻松搜索(并突出显示!)所有匹配手册页的美妙方式。这对我来说是一个游戏规则改变者。谢谢你,斯特凡!
对于那些可能感兴趣的人,这是脚本的关键部分(毫无疑问它可以改进;随时欢迎反馈):
编辑:我现在已经采纳了 Stéphane 的额外反馈。巨大的进步!
编辑:我进一步改进了这个解决方案,使其可以与 Ubuntu 20.04.4 LTS 和 macOS 12.6 一起使用,通过管道传输到ul
。
#!/bin/bash
arg_search="$1"
typeset -A seen=()
while IFS= read -ru3 filename; do
if (( ! seen[\$filename]++ )); then
# 'man -awK' sometimes returns bogus results due to searching through
# everything, including comments in the man source file, so filter
# these out. Note that this creates a secondary problem: legitimate
# results may get filtered out when the search term is two or more
# words spanning across lines. This can be solved with a multiline
# regex using `pcre2grep -M 'search\s+term`, but this is perhaps
# growing beyond the scope of things here.
{ man --no-hyphenation --no-justification --regex -- "$filename" | \
grep -iqE -- "$arg_search"; } || continue
# Print filename. Fill terminal width with highlighted background color.
filename_bar="$(printf '%s\t' "$filename" | expand -t $(tput cols))"
printf '\e[1;103;30m%s\e[0m\n' "$filename_bar"
# Per Stéphane's feedback, here's a cleaner version of the same for zsh:
# psvar=${(mr[COLUMNS])filename} print -P '%K{yellow}%F{black}%1v%k%f'
MAN_KEEP_FORMATTING=1 man \
--no-hyphenation --no-justification --regex -- "$filename" | \
ul | \
grep -iE --color=always -- "$arg_search"
fi
# 'unbuffer' seems to be required for macOS in order to unbuffer the output,
# as 'stdbuf -oL -eL' doesn't seem to work. Install on macOS using
# 'brew install expect' [sic], which contains unbuffer. This otherwise
# doesn't hurt anything on Ubuntu 20.04.4 LTS. Unbuffering the output of
# 'man -awK' is important because it can take a long time to run.
done 3< <(unbuffer man -awK --regex -- "${arg_search}")
答案1
尝试:
GROFF_SGR=1 man -P 'grep --color=always -C 3 pathspec' git
如果通过管道传输到grep
,您可能希望GROFF_SGR=1
(至少在基于 Debian 的系统上需要)使用 ANSI SGR 转义序列(如\e[1mBOLD\e[m
)来实现粗体/下划线,而不是传统的B\bBO\bOL\bLD\bD
,这会使 grep 变得困难。看Grep:从手册页搜索标题中的单词时出现意外结果了解详情。
请注意,寻呼机(此处)仅在标准输出转到终端grep
时运行。man
通过管道传输到诸如此类的命令less
会禁用该命令grep
和格式设置。
MAN_KEEP_FORMATTING
当我回答时,用于在我的测试中禁用 SGR 的设置Grep:从手册页搜索标题中的单词时出现意外结果那时,但现在似乎不再是这样了(至少在 Ubuntu 20.04 上不是)。
因此,要使用寻呼机,您可以这样做
GROFF_SGR=1 MAN_KEEP_FORMATTING=1 man git |
grep --color=always -C 3 pathspec | less -R
虽然它不是由 启动的man
,less
但未配置为显示相关的页脚行,或者您可以将内联 shell 脚本传递给-P
该调用grep
和pager
.
例如,与zsh
:
mangrep()
GROFF_SGR=1 CODE="
grep --color=always -C3 ${(j[ ])${(qq)@[2,-1]}} | pager
" man -P 'sh -c "eval \"$CODE\""' $1
然后例如:
mangrep git -i pathspecs
如果您pager
是less
,因为它是由 启动的man
,它将继承设置的LESS*
环境变量man
,如下所示:
LESS=-ix8RmPm Manual page git(1) ?ltline %lt?L/%L.:byte %bB?s/%s..?e (END):?pB %pB\%.. (press h for help or q to quit)$PM Manual page git(1) ?ltline %lt?L/%L.:byte %bB?s/%s..?e (END):?pB %pB\%.. (press h for help or q to quit)$
LESSCHARSET=utf-8
bash (4.4+) 等效项可能如下所示:
mangrep() {
local page=$1 IFS=' '
shift
GROFF_SGR=1 CODE="
grep --color=always -C3 ${*@Q} | pager
" man -P 'bash -c "eval \"$CODE\""' ${page:+"$page"}
}
(使用"$*"
andIFS=' '
而不是j[ ]
与空格连接,@Q
(需要bash
解码)而不是(qq)
(与 sh 兼容的引用),使用shift
并保存第一个参数$page
as@Q
不能与数组范围组合)。
允许man
(in zsh
) 的选项:
mangrep() {
local page=$@[(i)[^-]*]
GROFF_SGR=1 CODE="
grep --color=always -C3 ${(j[ ])${(qq)@[page+1,-1]}} | pager
" man -P 'sh -c "eval \"$CODE\""' "$@[1,page]"
}
然后例如:
mangrep -a printf -i precision
在所有手册页(传递给)中不区分precision
大小写(传递给)查找。i
-i
grep
a
printf
-a
man
使其成为脚本而不是函数:
#! /bin/zsh -
page=$@[(i)[^-]*]
GROFF_SGR=1 CODE="
grep --color=always -C3 ${(j[ ])${(qq)@[page+1,-1]}} | pager
" exec man -P 'sh -c "eval \"$CODE\""' "$@[1,page]"
然后您将能够从任何 shell(或非 shell)使用,而不仅仅是zsh
.
对您在编辑中发布的代码的一些评论:
[...]
man -w -a -K "$arg_search" | \
应该是man -w -a -K -- "$arg_search"
,否则您将无法搜索以开头的内容-
(除了使用诸如arg_search='[-]-foo'
作为解决方法之类的内容之外)。
stdbuf -oL -eL uniq | \
uniq
仅删除连续的重复项
xargs -d $'\n' -n 1 -I {} env bash -c "
-I
并且-n 1
是多余的。此外,bash
内联脚本可以采用多个参数,无需bash
为每个参数调用。
$( cat <<EOF
正如EOF
未引用的那样,扩展正在此处文档中执行,并且作为外壳代码争论。这是不好的做法,这是典型的代码注入漏洞。外部数据应该作为参数或环境变量传递。
filename='{}'
同样的, 的扩展(由xargs
){}
最终出现在 shell 代码中。
filename_length="\${#filename}" terminal_width="$(tput cols)" delta_length="\$(("\$terminal_width" - "\$filename_length"))" # Print filename, and fill width with highlighted background color. padding="\$(seq -s' ' "\$(("\$delta_length" + 1))" | \ tr -d '[:digit:]')" printf '\e[1;103;30m%s\e[0m' "\$filename\$padding"
相当复杂。我使用zsh
,那就是:
psvar=${(mr[COLUMNS])filename} print -P '%K{yellow}%F{black}%1v%k%f'
对于其他 shell,您还可以使用以下命令对字符串进行右填充:
printf '%s\t' "$string" | expand -t "$(tput cols)"
至少在 BSD 上以及像 zsh 的r
ight 填充扩展标志一样,当与m
标志一起使用时,会考虑每个字符的显示宽度(但不支持转义序列,因此着色序列不得包含在发送到的文本中expand
)。
GROFF_SGR=1 man --no-hyphenation --no-justification \ "\$filename" | grep --color=always "$arg_search"
[...]
我想你已经MAN_KEEP_FORMATTING
定义了?如果没有它,当管道传输到 时,格式应该会丢失grep
。
另请注意,man -K
使用 and 进行固定字符串搜索和扩展正则表达式搜索--regex
在任何一种情况下都不区分大小写,因此您需要选项-i
并添加--regex
到man
和-E
到grep
或添加-F
到grep
以使搜索逻辑在两者之间匹配。
所以,在这里,我宁愿这样做:
#! /bin/zsh -
ere=${1-GROFF_NO_SGR}
typeset -A seen=()
while IFS= read -ru3 filename; do
if (( ! seen[\$filename]++ )); then
psvar=${(mr[COLUMNS])filename} print -P '%K{yellow}%F{black}%1v%k%f'
GROFF_SGR=1 MAN_KEEP_FORMATTING=1 man --no-hyphenation \
--no-justification -l "$filename" |
grep -iF --color=always -C4 -- "$ere"
fi
done 3< <(man -awK -- "$ere")
答案2
我发现的唯一可以同时使用这两种方法的方法macOS 12.6 和 Ubuntu 20.04.4 LTS非常简单如下:
MAN_KEEP_FORMATTING=1 man git | ul
(我将 Stéphane Chazelas 的答案保留为已接受的答案,因为它要详细得多,并感谢您提供大量时间和专业知识。)