如何在有意保留格式的同時通過管道傳輸手冊頁(沒有分頁)?
最小的例子:
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 並讓它通過格式化(顏色/等)傳遞到標準輸出而無需分頁?**編輯:**感謝下面 Stéphane 的幫助,我現在有了一種輕鬆搜尋(並突出顯示!)所有匹配的手冊頁的漂亮方法。這對我來說是一個改變遊戲規則的人。謝謝你,斯蒂芬!
對於那些可能感興趣的人,這裡是腳本的關鍵部分(毫無疑問它可以改進;隨時歡迎回饋):
arg_search="GROFF_NO_SGR" # The reason for this complicated pipeline is that searching man pages can take # a very long time, so line buffer the output (using stdbuf) and immediately # process it, rather than waiting for the entire search to complete. man -w -a -K "$arg_search" | \ stdbuf -oL -eL uniq | \ xargs -d $'\n' -n 1 -I {} env bash -c " $( cat <<EOF filename='{}' 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" GROFF_SGR=1 man --no-hyphenation --no-justification \ "\$filename" | grep --color=always "$arg_search" EOF ) "
嘗試:
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
當我回答 Grep 時,在我的測試中用於禁用 SGR 的設置:當時從手冊頁的標題中搜尋單詞時出現意外結果,但似乎不再是這種情況(至少在 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
isless
,因為它是由 開始的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
(inzsh
) 的選項: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
在ll手冊頁(傳遞給)中查找
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
未引用的那樣,在此處的文件中正在執行擴展,並將其作為shell 程式碼參數傳遞。這是不好的做法,這是典型的程式碼注入漏洞。外部數據應作為參數或環境變數傳遞。filename='{}'
同樣,擴展 (by
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")