如何使用grep在--help输出中进行搜索?

当使用grepegrep来搜索带有--help参数的程序输出时,它会打印完整的输出而不是匹配的行。
示例:
ssh-keygen --help | grep "known_hosts"
unknown option -- -
usage: ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa | rsa1]
                  [-N new_passphrase] [-C comment] [-f output_keyfile]
       ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]
       ssh-keygen -i [-m key_format] [-f input_keyfile]
       ssh-keygen -e [-m key_format] [-f input_keyfile]
       ssh-keygen -y [-f input_keyfile]
       // etc

当搜索一个参数像ssh-keygen --help | grep "-p"时,grep会识别这个参数。转义破折号(即grep "\-p")没有帮助。
例子:
ssh-keygen --help | grep "-p"         
grep: invalid option -- 'p'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
unknown option -- -
usage: ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa | rsa1]
                  [-N new_passphrase] [-C comment] [-f output_keyfile]
       ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]
       ssh-keygen -i [-m key_format] [-f input_keyfile]
       ssh-keygen -e [-m key_format] [-f input_keyfile]
       ssh-keygen -y [-f input_keyfile]
       ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile]
       ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]
       ssh-keygen -B [-f input_keyfile]

如何解决这个问题?感谢任何帮助!

如何在终端命令中获取帮助? - dessert
3个回答

ssh-keygen命令没有--help选项,因此它会打印“未知选项”错误,默默地想着“RTFM”,然后输出帮助信息。它不是在标准输出(stdout)上输出,而是在标准错误(stderr)上输出,这个输出不能通过|管道传递,只能通过|&(这是bash中的一种简写形式,等同于2>&1 |)来传递:
$ ssh-keygen --help |& grep "known_hosts"
       ssh-keygen -F hostname [-f known_hosts_file] [-l]
       ssh-keygen -H [-f known_hosts_file]
       ssh-keygen -R hostname [-f known_hosts_file]

一个完全不同的问题是,grep会将以连字符开头的搜索表达式识别为选项。幸运的是,grep是许多命令中能够识别“选项结束”--选项,并将其后的所有内容作为参数而不是选项的命令之一。
$ ssh-keygen --help |& grep -- -p
       ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]

man grep甚至没有提到它,但这是来自bash手册的选项描述:

--表示选项的结束,并禁用进一步的选项处理。在--之后的任何参数都被视为文件名和参数。

grep还提供了另一种处理以“-”开头的模式的方法:使用-e选项并将模式作为其参数,因此以下方式同样可行:

$ ssh-keygen --help |& grep -e -p
       ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]

进一步阅读


1很棒的帖子,但是你为什么认为grep手册应该提到shell如何处理--呢?它也没有提到其他shell功能,比如文件名扩展、变量扩展、命令替换等。在命令执行之前,shell会做很多事情。我认为grep手册不是这些细节的合适位置。 - miracle173
@miracle173 bash 和它的一些内置命令理解 --,但是 shell 对于 grep -- -p 什么也不做(那会是什么呢?)。只有 grep 理解这个选项及其特殊含义,因此它的手册应该将其列为一个选项。 - dessert
1你是对的。我现在明白了,它只限于一些内置功能。所以实际上这是一个grep的特性。 - miracle173
通过实施grep后面的POSIX Utility Syntax Guideline 10,所以这不是他们的主意,但还是... - dessert

如果你需要关于ssh-keygen命令的帮助,请尝试以下内容。
man ssh-keygen | grep known_hosts

或者,你可以在命令行中输入man ssh-keygen,然后按下/键并输入搜索词,例如"kno",按下Enter,使用n继续查找下一个匹配项(有关使用man的更多信息,请参阅man man)。请注意,man搜索只会向下搜索,因此在开始新的搜索之前,请使用PgUpHome键返回到手册条目的开头。

你使用了一个不存在的选项来调用ssh-keygen命令。这是一个错误,错误输出会显示在stderr上。看起来ssh-keygen没有一个常规选项来输出它的用法:如果有的话(就像GNU程序默认使用--help选项一样),那个“常规”输出将显示在stdout上,并且可以通过你使用的管道访问。
你可以通过使用ssh-keygen --help 2>&1 | grep -e "-p" 来绕过这个问题:2>&1将stderr重定向到stdout,这样管道就可以捕获它,-e作为grep的选项意味着“以下内容是要使用的正则表达式,即使它看起来像一个选项”。
man ssh-keygen应该更好地获取用法,并且默认会通过管道传递给less,你可以使用/在上下文中搜索正则表达式,通常这是更好的选择。