18

I'm trying to come up with a way to find a specific flag in a man-page. Usually, I type '/' to search for something, followed by something like '-Werror' to find a specific flag. The thing is though that there are man-pages (gcc is the one motivating me right now) that have a LOT of references to flags in their text, so there are a lot of occurrences.

It's not that big of a deal, but maybe it can be done a bit better. I thought of looking for something like '-O\n' but it didn't work (probably because the man program doesn't use C escapes?) Then I've tried something like man gcc | grep $'-O\n', since I kind of recall that a single-quoted string preceded by a dollar sign haves bash interpret common C escapes... It' didn't work, grep echoed the whole man-page.

That's what has brought me here: why? or rather, can this be done?

fedorqui
  • 275,237
  • 103
  • 548
  • 598
ferhtgoldaraz
  • 1,693
  • 3
  • 15
  • 20
  • 4
    An alternative is to use http://explainshell.com, which, given a command with options, explains each option a using information extracted from `man` pages, using a nice GUI; here's the result for `gcc -O`: http://explainshell.com/explain?cmd=gcc+-O. Note that the `man` pages used are Ubuntu's, and the information therefore applies to _GNU_ utilities. – mklement0 Jul 27 '14 at 16:47
  • 1
    I found out about explainshell a while ago, and I am loving it, thanks. Good suggestion. – ferhtgoldaraz Jul 27 '14 at 18:16
  • So basically, you just use `grep -- -n` or `grep -e -n` to search for `-n` explicitly instead of passing it as a flag to `grep`. – Alex W Mar 15 '17 at 03:42

8 Answers8

12

rici's helpful answer explains the problem with the original approach well.

However, there's another thing worth mentioning:

man's output contains formatting control characters, which interfere with text searches.

If you pipe to col -b before searching, these control characters are removed - note the side effect that the search results will be plain-text too.

However, grep is not the right tool for this job; I suggest using awk as follows to obtain the description of -O:

man gcc | col -b | awk -v RS= '/^\s+-O\n/'
  • RS= (an empty input-record separator) is an awk idiom that breaks the input into blocks of non-empty lines, so matching the option at the start of such a block ensures that all lines comprising the description of the option are returned.

If you have a POSIX-features-only awk such as BSD/OSX awk, use this version:

man gcc | col -b | awk -v RS= '/^[[:blank:]]+-O\n/'

Obviously, such a command is somewhat cumbersome to type, so find generic bash function manopt below, which returns the description of the specified option for the specified command from its man page. (There can be false positives and negatives, but overall it works pretty well.)

Examples:

manopt gcc O          # search `man gcc` for description of `-O`
manopt grep regexp    # search `man grep` for description of `--regexp`
manopt find '-exec.*' # search `man find` for all actions _starting with_ '-exec'

bash function manopt() - place in ~/.bashrc, for instance:

# SYNOPSIS
#   manopt command opt
#
# DESCRIPTION
#   Returns the portion of COMMAND's man page describing option OPT.
#   Note: Result is plain text - formatting is lost.
#
#   OPT may be a short option (e.g., -F) or long option (e.g., --fixed-strings);
#   specifying the preceding '-' or '--' is OPTIONAL - UNLESS with long option
#   names preceded only by *1* '-', such as the actions for the `find` command.
#
#   Matching is exact by default; to turn on prefix matching for long options,
#   quote the prefix and append '.*', e.g.: `manopt find '-exec.*'` finds
#   both '-exec' and 'execdir'.
#
# EXAMPLES
#   manopt ls l           # same as: manopt ls -l
#   manopt sort reverse   # same as: manopt sort --reverse
#   manopt find -print    # MUST prefix with '-' here.
#   manopt find '-exec.*' # find options *starting* with '-exec'
manopt() {
  local cmd=$1 opt=$2
  [[ $opt == -* ]] || { (( ${#opt} == 1 )) && opt="-$opt" || opt="--$opt"; }
  man "$cmd" | col -b | awk -v opt="$opt" -v RS= '$0 ~ "(^|,)[[:blank:]]+" opt "([[:punct:][:space:]]|$)"'
}

fish implementation of manopt():

Contributed by Ivan Aracki.

function manopt 
  set -l cmd $argv[1]
  set -l opt $argv[2] 
  if not echo $opt | grep '^-' >/dev/null
    if [ (string length $opt) = 1 ] 
      set opt "-$opt"
    else
      set opt "--$opt"
    end
  end
  man "$cmd" | col -b | awk -v opt="$opt" -v RS= '$0 ~ "(^|,)[[:blank:]]+" opt "([[:punct:][:space:]]|$)"'
end
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • @AlexanderWeickmann: Indeed it doesn't, because `jq`'s `man` page is formatted differently than the pages for standard utilities such as `ls`. – mklement0 Nov 20 '19 at 21:19
  • I found I had to edit this a bit. Using your example I had to change it to `MANWIDTH=160 man gcc | col -b | awk -v RS= '/-O,/'`. The previous example, with MANDWITH set, outputs nothing, I'm not sure why. I'd be interested in knowing, but in any case, thanks! – BrotherJack May 10 '20 at 18:33
6

I suspect you didn't actually use grep $'-O\n', but rather some flag recognized by grep.

From grep's point of view, you are simply passing an argument, and that argument starts with a - so it's going to be interpreted as an option. You need to do something like grep -- -O$ to explicitly flag the end of the list of options, or grep -e -O$ to explicitly flag the pattern as a pattern. In any event, you cannot include a newline in a pattern because grep patterns are actually lists of patterns separated by newline characters, so the argument $'foo\n' is actually two patterns, foo and the empty string, and the empty string will match every line.

Perhaps you searched for the flag -e since that takes a pattern as an argument, and giving it a newline as an argument will cause grep to find every line in the whole file.

For most GNU programs, such as gcc, you might find the info interface easier to navigate in, since it includes reference links, tables of contents, and even indices. The info gcc document includes an index of options, which is very useful. In some linux distributions, and somewhat surprisingly since they call themselves GNU/linux distributions, it's necessary to separately install info packages although man files are distributed with the base software. The debian/ubuntu package containing the gcc info files is called gcc-doc, for example. (The use of the -doc suffix to the package name is quite common.)

In the case of gcc you can rapidly find an option using a command like:

info gcc "option index" O

or

info gcc --index-search=funroll-loops

For programs with fewer options, it's usually good enough to use info's -O option:

info -O gawk
rici
  • 234,347
  • 28
  • 237
  • 341
  • I just tried `man gcc | grep -- $'-O\n'` and didn't work. But with `grep -- -e '-O$' it does... Although now I feel really stupid, since that evidently returns a line that only contains '-O', which is not usefull at all... – ferhtgoldaraz Oct 05 '13 at 18:48
  • 2
    @ferhtgoldaraz: You probably want to use `-A1` or some such ("`-A NUM` Print NUM lines of trailing context after matching lines.") – rici Oct 05 '13 at 20:21
  • @rici: Thanks for the clarifying update. `-e` doesn't actually _necessarily_ take a _regex_ as its argument (despite its long option name, `--regexp`) - it's simply an alternative mechanism for passing _multiple_ patterns as _separate options_ rather than a _single multi-line string_. Thus, for instance, with `-F` (or invoked as `fgrep`) the `-e` arguments are _fixed_ (literal) strings. Another way of putting it: a pattern passed to `-e` is treated the same as one without it (and passing a multi-line string to `-e` also results in multiple patterns). – mklement0 Jul 26 '14 at 03:48
  • @mklement0: yeah, I didn't fix the word `regex` in the unedited text. For the sake of thoroughness I'll change the word. – rici Jul 26 '14 at 05:22
  • @mklement0: ... and add more examples of `info`, which is actually a lot more useful for monstrous docs like gcc and bash. – rici Jul 26 '14 at 05:38
  • Thanks. Looks handy for `gcc` (I actually got errors installing `gcc-doc` on Ubuntu 14.04 and only the `--index-search` option works as expected), but support for these options with utilities such as `awk`, `grep`, `sed`, `find`, ... is spotty and inconsistent, unfortunately. E.g., most act no different when invoked with `-O`, and some make it hard to get to a list of options (e.g., `grep`); `--index-search` works with `sed`, but not `awk`, ... – mklement0 Jul 26 '14 at 06:24
  • I like your approach - jumping to the information of interest in context of the documentation - better than mine (extracting an isolated piece of information), but it looks like there's no unified solution. – mklement0 Jul 26 '14 at 06:25
  • @mklement0: `info` falls back to manpages, so you need to call `gawk` `gawk` if you want `info` about it. (You probably have a man alias.) I agree that some of the info pages are not as well-organized as others, and ubuntu's doc packages are not what one might expect in a developer-oriented distro. But that's not ubuntu's purpose. Anyway, "patches welcome". Oh, and if --index-search doesn't find the right index entry, type a comma. – rici Jul 26 '14 at 06:45
  • Thanks; re `--index-search`: type a comma where? – mklement0 Jul 26 '14 at 07:00
  • @mklement0: after it shows you the wrong index entry. `,` means "show the next similar index entry". By the way, Debian/Ubuntu consider `info`'s own `info` file non-free, so you have to `apt-get install texinfo-doc-nonfree` to get it. Far from obvious. – rici Jul 26 '14 at 07:03
  • Got it, thanks; however, `info --index-search=...` doesn't seem to find _anything_ for `gawk` and `find`, for instance. By contrast, works OK for `sed` and `cut`, for instance. As a minor point of interest: OSX is _also_ running _GNU_ `info` (version 4.8 as of OSX 10.9.4). – mklement0 Jul 26 '14 at 14:43
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/58061/discussion-between-rici-and-mklement0). – rici Jul 26 '14 at 15:45
  • I think `info --vi-keys` should be mentioned, since it turns on normal (`man`-like) keybindings for `info` – UTF_or_Death Mar 03 '17 at 11:04
2

The thing is that 'man' uses a pager, commonly 'less', whose man-page states:

/pattern
    Search  forward  in  the file for the N-th line containing the pattern.
    N defaults to 1.  The pattern is a regular expression, as recognized by the
    regular expression library supplied by your system.  The search starts at the
    first line displayed (but see the -a and -j options, which change this).

So one could try and look for '-O$' in a man-page to find a flag that lives alone in it's own line. Although, it is common for a flag to be followed by text in the very same line, so this is not guaranteed to work.

The issue with grep and $'-O\n' is still a mystery though.

ferhtgoldaraz
  • 1,693
  • 3
  • 15
  • 20
  • I don't intend to trick the system or anything by adding an answer to my own question, I actually looked it up first and came up with [this meta stack overflow question](http://meta.stackexchange.com/questions/12513/should-i-not-answer-my-own-questions) addressing the possible issue. – ferhtgoldaraz Oct 05 '13 at 14:40
1
man gcc | grep "\-" 

This works pretty well, as it displays all flags and usually not much more.

Edit: I notice I didn't completely answer your question, but I hope my suggestion can be considered as a nice alternative.

Nick Knuckle
  • 106
  • 10
  • 2
    The backslash in that search pattern is pointless. And with or without the backslash, it returns 5160 of the 12737 lines of `man gcc`. You can cut it down a bit by limiting it to things that look more like options: `man gcc | grep ' -[[:alpha::]]'` returns 3788 lines, for example. Of course, gcc has a *lot* of options, and you rarely really want to look at all of them. – rici Jul 26 '14 at 05:44
1

I use folowing:

man some_command | col -b | grep -A5 -- 'your_request'

Examples:

  • man man | col -b | grep -A5 -- '-K'

  • man grep | col -b | grep -A5 -- '-e patt'

You can make alias for it.

WebBrother
  • 1,447
  • 20
  • 31
1

The manly Python utility is very convenient for getting a quick explanation of all options used in a given command.

Note that it only outputs the first paragraph of the option descriptions.

pip install manly
$ manly blkid /dev/sda -o value -p

blkid - locate/print block device attributes
============================================

      -o, --output format
              Use  the  specified output format.  Note that the order of vari‐
              ables and devices is not fixed.  See also option -s.  The format
              parameter may be:

      -p, --probe
              Switch to  low-level  superblock  probing  mode  (bypassing  the
              cache).
Martin Valgur
  • 5,793
  • 1
  • 33
  • 45
1

a double dash (--) is used in most bash built-in commands and many other commands to signify the end of command options

https://unix.stackexchange.com/a/11382/204245

Without the double-dash, grep is trying to use whatever flag you are looking for:

$ man curl | grep -c # Looks for this c flag, but can't find one so throws the error below.
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
    [-e pattern] [-f file] [--binary-files=value] [--color=when]
    [--context[=num]] [--directories=action] [--label] [--line-buffered]
    [--null] [pattern] [file ...]

If you use double-dash to signify the end of input to grep, it works a bit better, but you still end up with every occurrence of the match:

$ man curl | grep -- -c
       --cacert <file>
              certs file named 'curl-ca-bundle.crt', either in the same direc-
       --capath <dir>
              curl to make SSL-connections much more  efficiently  than  using
              --cacert if the --cacert file contains many CA certificates.
       --cert-status
       --cert-type <type>
       -E, --cert <certificate[:password]>
       --ciphers <list of ciphers>
# ...many more matches......

So simply wrap the flag in quotes and throw a space before it to only match the -c flag:

$ man curl | grep -- " -c"
       -c, --cookie-jar <filename>

This has driven me insane for years. Hope this helps.

corysimmons
  • 7,296
  • 4
  • 57
  • 65
0

man is based on an environment variable (EDITOR if I'm not mistaking). You can change this from more (the default value) to, e.g., emacs, and then while using man an emacs session gets opened on your system, where you can search and browse as you like.

Dominique
  • 16,450
  • 15
  • 56
  • 112