2

In Bash I have an alias (to run nvim when I type vim). But when I type man vim I get the man for vim, not nvim. Sort of makes sense, but of course what I really want is "the manual for what I get if I run vim in the shell or from a script" not "the manual for a program I don't use". Is there some way to configure aliases or man to work this way, or am I expected to remember/lookup aliases each time I run man, to make sure I am looking up info on the correct version of the correct app?

  • 1
    If you think you might be running an alias, type alias the-command and see. – Jeff Schaller Sep 28 '17 at 9:48
  • There's no think about it; it's in the first few words of my question. My concern is that I have many aliases and have no interested in memorizing them or going through my .bashrc before using man. – user13757 Sep 28 '17 at 10:05
  • Out of curiosity - why alias vim and not vi? – Thorbjørn Ravn Andersen Sep 28 '17 at 10:55
  • @ThorbjørnRavnAndersen I started using vim and neovim recently enough that I don't think I've ever typed vi! – user13757 Sep 29 '17 at 11:02
5

No, man cannot really look up all your aliases and serve the manpage of the program you've aliased. What you could do instead is to set up another alias for the manpage:

alias manvim="man nvim"  
  • 3
    @DrEval because aliases are shell and user-specific while man is global. It has no knowledge of your aliases, functions, scripts etc. – terdon Sep 28 '17 at 10:04
  • 1
    @DrEval I have alias emacs='$VISUAL'; alias vi='$VISUAL'; alias vim='$VISUAL' on many of my machines. Would you propose man try to expand these (if it could even see them) to try to figure out what command that refers to? – Fox Sep 28 '17 at 10:09
  • 1
    @DrEval Define "simple". In my case, if $VISUAL happens to be nano, then man emacs would display the wrong page, and man '$VISUAL' would say there is no manual entry for $VISUAL. If it is to expand the variable, it has to know how, and then you're reimplementing half the shell just to display a manpage (possible hyperbole) – Fox Sep 28 '17 at 10:14
  • 2
    @DrEval I don't know about terdon's case, but in mine, the output of alias vi is literally alias vi='$VISUAL'. That is, the variable itself is the output, not its contents – Fox Sep 28 '17 at 10:24
  • 2
    If you are really desperate, you can copy /usr/share/man/man1/vim.1.gz to somewhere independent and then copy your nvim man page to /usr/share/man/man1/vim.1.gz. After this run "mandb" – Raman Sailopal Sep 28 '17 at 10:29
1

In bash, you can use type vim to look up what happens when you type vim at the prompt. You can thus replace man with a shell function that checks its argument and "does the right thing".

932% type ls
ls is hashed (/bin/ls)
933% type vim
vim is aliased to `nvim'

As you can see the output of type would require a bit of parsing and case-dependent logic, but it is certainly not a big deal for simple cases. The alias expansion could consist of more than one word (e.g. I alias lf to ls -AF), but that's easy to handle too.

It gets harder if the alias is a pipeline (I'd probably show the manpage for the first command and hope for the best), and hopeless if your command is a shell function rather than an alias. So I'd unpack aliases and pass everything else to man without modifications. Here's a proof of concept (supports one argument only, and no options to man):

function man {
    # Find out if the command is an alias, an executable, etc.
    local cmd

    p=$(type $1)
    case `set $p; echo $3` in
       aliased) cmd=($(set `command alias $1`; echo $2 | sed "s/.*='\([^ ]*\).*/\1/"));;

       *) cmd=$1;;
    esac

    command man $cmd
}

Define this, and man vim will look up your alias and show you the manpage for nvim, as you ask.

0

If you shell handles aliases this way:

$ type vim
vim is aliased to `nvim'
$ type -t vim
alias

then try this. The following shell function will check if its argument is an alias. If so, it will extract the first blank-delimited word of the alias and run man on that.

man() {
  cmd="$1"
  if [ "$(type -t "$cmd")" == "alias" ]
  then cmd=$(type "$cmd" | sed -e 's/.*`//' -e "s/[ '].*//")
  fi
  command man $cmd
}

A more comprehensive solution would incorporate $IFS instead of just looking for blank and would allow aliases that contain ` and '.

0

This is a bad idea. One can use a shell function that may or may not find the aliased command. I instead almost always do not override the default name for things, especially not to make the command run some completely different command. Too many rakes to step on. With this warning in mind, in ZSH this function might look something like

# test aliases, for testing
# simple no args
alias emacs=ls
# with flags; need to pick first word and hope that's a command...
alias nano='ls -al'
# and oops there's also the ENV prefix form...
alias notepad='ASDF=blah ls -F'
# and also be sure to test with something-that-is-not-an-alias ...

# TODO call this `man` to actually override the man
function crazyman {
  local -a cmd args

  # one may simply type `man ... foo` or there could also be multiple
  # man pages to be viewed `man ... foo bar` so must iterate over all
  # the hopefully-not-options-or-section-names arguments and try alias
  # lookups and all such... `man ls -w` may also be legal depending on
  # the getops, by the way.
  while :; do
    if [[ -n $1 ]]; then
      while :; do
        # try to skip over `man 1 foo` or `man -w foo` forms to find what
        # is hopefully the foo command
        #
        # TODO 'n' section for TCL complicated as there could also be a
        # 'man n' command alongside "man n expr" or whatnot; this assumes
        # there is no 'man n' page that would ever be looked up. Other
        # non-numeric-prefixed man section names may also need to be
        # handled here, depending on the vendor...
        if [[ $1 =~ "^[0-9-]|^n$" ]]; then
          args+=($1)
          shift
        else
          break
        fi
      done

      cmd=(${(z)aliases[$1]})

      if (( #cmd )); then
        # aliases might be simple foo='bar ...' or more complicated
        # foo='ENV=asdf ... bar ...' where we need to dig to try to find
        # the bar command, and perhaps other complications as well :/
        # I did say this was a bad idea...
        while :; do
          if [[ $cmd[1] =~ "=" ]]; then
            shift cmd
          else
            break
          fi
        done
        args+=($cmd[1])
      else
        args+=($1)
      fi
      shift
    else
      break
    fi
  done

  command man $args
}

With the command man $args instead replaced with print -l command man $args, some manual testing (proper unit tests would be greatly advisable given the number of edge cases in the above code):

% crazyman emacs
command
man
ls
% crazyman nano 
command
man
ls
% crazyman notepad
command
man
ls
% crazyman notepad nano
command
man
ls
ls
% crazyman nosuchalias
command
man
nosuchalias
% 

Porting this code to other shells left as exercise to reader. Or, simplify and do not use this code given the complexity for not very much of a gain.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy