Dis*_*ame 33 command-line osx freebsd man
所有 shell 内置函数共享相同的手册页:
BUILTIN(1) BSD General Commands Manual BUILTIN(1)
NAME
builtin, !
Run Code Online (Sandbox Code Playgroud)
等等。
然后有一小段文字描述了什么是 shell 内置函数,然后是一个看起来像这样的列表:
Command External csh(1) sh(1)
! No No Yes
% No Yes No
Run Code Online (Sandbox Code Playgroud)
但是如果我们这样做,man grep我们会得到诸如
等等。
难道 shell 内置函数没有自己的历史、描述和参数,比如-A或-r?为什么手册页中没有提供,我将如何学习正确有效地使用它们?
ter*_*don 26
因为内置函数是 shell 的一部分。他们拥有的任何错误或历史都是 shell 本身的错误和历史。它们不是独立的命令,也不存在于它们内置的 shell 之外。
bash至少,等效的是help命令。例如:
$ help while
while: while COMMANDS; do COMMANDS; done
Execute commands as long as a test succeeds.
Expand and execute COMMANDS as long as the final command in the
`while' COMMANDS has an exit status of zero.
Exit Status:
Returns the status of the last command executed.
Run Code Online (Sandbox Code Playgroud)
所有 bash 内置函数都有help页面。甚至help自己:
$ help help
help: help [-dms] [pattern ...]
Display information about builtin commands.
Displays brief summaries of builtin commands. If PATTERN is
specified, gives detailed help on all commands matching PATTERN,
otherwise the list of help topics is printed.
Options:
-d output short description for each topic
-m display usage in pseudo-manpage format
-s output only a short usage synopsis for each topic matching
PATTERN
Arguments:
PATTERN Pattern specifiying a help topic
Exit Status:
Returns success unless PATTERN is not found or an invalid option is given.
Run Code Online (Sandbox Code Playgroud)
受@mikeservsed脚本的启发,这里有一个小函数,可以使用 Perl 打印手册页的相关部分。将此行添加到 shell 的初始化文件(~/.bashrc对于 bash):
manperl(){ man "$1" | perl -00ne "print if /^\s*$2\b/"; }
Run Code Online (Sandbox Code Playgroud)
然后,通过给它一个手册页和一个部分的名称来运行它:
$ manperl bash while
while list-1; do list-2; done
until list-1; do list-2; done
The while command continuously executes the list list-2 as long as the last command in the list list-1 returns an exit
status of zero. The until command is identical to the while command, except that the test is negated; list-2 is exe?
cuted as long as the last command in list-1 returns a non-zero exit status. The exit status of the while and until
commands is the exit status of the last command executed in list-2, or zero if none was executed.
$ manperl grep SYNOPSIS
SYNOPSIS
grep [OPTIONS] PATTERN [FILE...]
grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]
$ manperl rsync "-r"
-r, --recursive
This tells rsync to copy directories recursively. See also --dirs (-d).
Run Code Online (Sandbox Code Playgroud)
虽然某些 shell 内置函数确实可能在完整手册中很少显示——特别是对于那些bash你可能只在 GNU 系统上使用的特定内置函数(GNU 的人,作为一项规则,不相信man和更喜欢他们自己的info页面) - 绝大多数 POSIX 实用程序 - shell 内置程序或其他 - 在 POSIX 程序员指南中得到了很好的体现。
这是我的底部摘录man sh (大概有 20 页左右......)

所有这些都在那里,和其他人没有提到这样的set,read,break...好,我不需要给它们命名所有。但请注意(1P)右下角 - 它表示 POSIX 类别 1 手册系列 - 这些是man我正在谈论的页面。
可能你只需要安装一个包?这对于 Debian 系统来说看起来很有希望。虽然help很有用,但如果你能找到它,你绝对应该得到那个POSIX Programmer's Guide系列。它可能非常有帮助。它的组成页面非常详细。
除此之外,shell 内置函数几乎总是列在特定 shell 手册的特定部分中。zsh,例如,有一个完整的单独man页面 - (我认为它总共有 8 或 9 个左右的单独zsh页面 - 包括zshall很大的页面。)
你grep man当然可以:
man bash 2>/dev/null |
grep '^[[:blank:]]*read [^`]*[-[]' -A14
read [-ers] [-a aname] [-d delim] [-i text] [-n
nchars] [-N nchars] [-p prompt] [-t timeout] [-u
fd] [name ...]
One line is read from the standard input, or
from the file descriptor fd supplied as an
argument to the -u option, and the first
word is assigned to the first name, the sec?
ond word to the second name, and so on, with
leftover words and their intervening separa?
tors assigned to the last name. If there
are fewer words read from the input stream
than names, the remaining names are assigned
empty values. The characters in IFS are
used to split the line into words using the
same rules the shell uses for expansion
Run Code Online (Sandbox Code Playgroud)
...这与我以前搜索 shellman页面时所做的非常接近。但在大多数情况下help是相当不错的bash。
我最近一直在sed编写一个脚本来处理这种事情。这就是我如何抓住上图中的部分。它仍然比我喜欢的要长,但它正在改进 - 并且非常方便。在当前的迭代中,它将非常可靠地提取上下文相关的文本部分,以根据命令行上给定的 [a] 模式 [s] 与部分或小节标题匹配。它为输出着色并打印到标准输出。
它通过评估缩进级别来工作。非空的输入行一般会被忽略,但是遇到空行就开始注意了。它从那里收集行,直到它确认当前序列在另一个空行出现之前肯定比它的第一行缩进得更远,否则它会放弃线程并等待下一个空白。如果测试成功,它会尝试将引导行与其命令行参数进行匹配。
这意味着匹配模式将匹配:
heading
match ...
...
...
text...
Run Code Online (Sandbox Code Playgroud)
..和..
match
text
Run Code Online (Sandbox Code Playgroud)
..但不是..
heading
match
match
notmatch
Run Code Online (Sandbox Code Playgroud)
..或者..
text
match
match
text
more text
Run Code Online (Sandbox Code Playgroud)
如果可以匹配,它就会开始打印。它将从它打印的所有行中去除匹配行的前导空白 - 因此,无论它发现该行的缩进级别如何,它都会像在顶部一样打印它。它将继续打印,直到遇到与其匹配行相同或小于缩进级别的另一行 - 因此整个部分仅通过标题匹配被抓取,包括任何/所有小节,它们可能包含的段落。
所以基本上,如果你要求它匹配一个模式,它只会针对某种主题标题进行匹配,并且会着色和打印它在匹配标题的部分中找到的所有文本。除了第一行的缩进之外,它不会保存任何内容 - 因此它可以非常快地处理\n几乎任何大小的 ewline 分隔输入。
我花了一段时间才弄清楚如何递归到如下副标题:
Section Heading
Subsection Heading
Run Code Online (Sandbox Code Playgroud)
但我最终解决了它。
不过,为了简单起见,我确实不得不重新设计整个过程。虽然之前我有几个小循环以稍微不同的方式做大部分相同的事情以适应它们的上下文,但通过改变它们的递归方式,我设法对大部分代码进行了去重。现在有两个循环 - 一个打印和一个检查缩进。两者都依赖于相同的测试——测试通过时打印循环开始,当测试失败或从空行开始时缩进循环接管。
整个过程非常快,因为大多数时候它只是/./d删除任何非空白行并移动到下一行 - 甚至zshall是立即填充屏幕的结果。这没有改变。
无论如何,到目前为止,它非常有用。例如,read上面的事情可以这样做:
mansed bash read
Run Code Online (Sandbox Code Playgroud)
...它得到了整个块。它可以采用任何模式或其他任何东西,或多个参数,尽管第一个始终是man它应该搜索的页面。这是我完成后的一些输出的图片:
mansed bash read printf
Run Code Online (Sandbox Code Playgroud)

...两个块都完整返回。我经常像这样使用它:
mansed ksh '[Cc]ommand.*'
Run Code Online (Sandbox Code Playgroud)
...它非常有用。此外,获取SYNOPS[ES]使它非常方便:

如果您想试一试,那就在这里 - 如果您不这样做,我不会责怪您。
mansed() {
MAN_KEEP_FORMATTING=1 man "$1" 2>/dev/null | ( shift
b='[:blank:]' s='[:space:]' bs=$(printf \\b) esc=$(printf '\033\[') n='\
' match=$(printf "\([${b}]*%s[${b}].*\)*" "$@")
sed -n "1p
/\n/!{ /./{ \$p;d
};x; /.*\n/!g;s///;x
:indent
/.*\n\n/{s///;x
};n;\$p;
/^\([^${s}].*\)*$/{s/./ &/;h; b indent
};x; s/.*\n[^-[]*\n.*//; /./!x;t
s/[${s}]*$//; s/\n[${b}]\{2,\}/${n} /;G;h
};
#test
/^\([${b}]*\)\([^${b}].*\n\)\1\([${b}]\)/!b indent
s//\1\2.\3/
:print
/^[${s}]*\n\./{ s///;s/\n\./${n}/
/${bs}/{s/\n/ & /g;
s/\(\(.\)${bs}\2\)\{1,\}/${esc}38;5;35m&${esc}0m/g
s/\(_${bs}[^_]\)\{1,\}/${esc}38;5;75m&${esc}0m/g
s/.${bs}//g;s/ \n /${n}/g
s/\(\(${esc}\)0m\2[^m]*m[_ ]\{,2\}\)\{2\}/_/g
};p;g;N;/\n$/!D
s//./; t print
};
#match
s/\n.*/ /; s/.${bs}//g
s/^\(${match}\).*/${n}\1/
/../{ s/^\([${s}]*\)\(.*\)/\1${n}/
x; s//${n}\1${n}. \2/; P
};D
");}
Run Code Online (Sandbox Code Playgroud)
简而言之,工作流程是:
\newline 字符的行都将从输出中删除。
\n输入模式空间中永远不会出现 ewline 字符。它们只能作为编辑的结果。:print和:indent都是相互依赖的闭环,是获得\newline的唯一方法。
:print如果一行的前导字符是一系列空格后跟一个\newline 字符,则循环开始。:indent的循环从空白行开始 - 或在:print失败的循环行上#test- 但从其输出中:indent删除所有前导空白 + \newline 序列。:print开始,它将继续拉入输入行,将前导空白去除到其循环中第一行的数量,将重击和欠击退格转义转换为彩色终端转义,并打印结果直到#test失败。:indent开始之前,它首先检查h旧空间是否有任何可能的缩进延续(例如子节),然后只要#test失败就继续拉入输入并且第一行之后的任何行继续匹配[-。当第一行之后的行与该模式不匹配时,它将被删除 - 随后所有行都将被删除,直到下一个空行。#match并#test桥接两个闭环。
#test当前导空白系列短于\n行序列中紧随其后的最后一个ewline的系列时,通过。#match将\n开始:print循环所需的前导ewlines 前置到任何:indent与任何命令行参数匹配的输出序列。那些不呈现为空的序列 - 产生的空行被传递回:indent.