21

About 5 times a day, I type "vi" when I meant "cd", and end up opening a directory in vi. It's making me NUTS. It seems like there should be a way to detect when I type in "vi + directory" and automatically change it to "cd + directory". Thoughts?

6
  • 1
    I gave an alternative that you may find interresting as well ^^ (one that let you correct the source of the problem, while avoiding getting irritated until then ^^) Commented Jan 16, 2014 at 9:58
  • Related stackoverflow.com/questions/16073807/…
    – user13107
    Commented Jan 16, 2014 at 12:18
  • 1
    It also frustrated me a lot, till I discovered that you can use Enter and arrows to navigate to the file inside the folder. When you click Enter while being on it it opens. Commented Jan 16, 2014 at 12:51
  • 1
    With only a small amount of facetiousness: change to zsh. Set it up so that when you type a directory name it changes into that directory. Use suffix aliases so that when you type *.sh, *.c, *.config whatever it opens the relevant file in vi. The caveat here is of course that you may find yourself omitting "vi" or "cd" in an unfamiliar shell.
    – mkingston
    Commented Jan 16, 2014 at 17:25
  • 3
    How does this happen?
    – jfa
    Commented Jan 16, 2014 at 20:27

4 Answers 4

38

With the assumption that you call vi with the directory as the last argument:

vi() {
    if [[ -d ${!#} ]]; then
        cd "$@"
    else 
        command vi "$@"
    fi
}
9
  • 2
    @Alex I guess this is both perfect for the rare cases you typed "vi" incorrectly instead of "cd", while at the same time teach you to always type "vi" now ;) [ie, I hope you don't often have to use another server/machine where that function will not be there to save you stress...] [+1 for that answer, though, it's what I wanted to answer as well, except I'd just test for "${1}" [and then cd "${1}"] instead of "${!#}" ...] Commented Jan 16, 2014 at 9:08
  • 5
    @OlivierDulac Agreed -- similarly dangerous is aliasing rm to rm -i, which is the default in many distributions. I generally think that the best way to solve problems is to solve the user rather than to work around them.
    – Chris Down
    Commented Jan 16, 2014 at 9:11
  • 3
    @OlivierDulac aliasing rm to rm -i might have saved you some trouble in the past but might (and probably will) get you in much more trouble in the future ...
    – jlliagre
    Commented Jan 16, 2014 at 11:25
  • 1
    @Alex Well, you did say vi in the question...
    – Chris Down
    Commented Jan 20, 2014 at 6:38
  • 2
    @crisron: ${!#} indirectly references the final argument, and command is only necessary to avoid function recursion in this instance.
    – Chris Down
    Commented Jan 28, 2014 at 2:28
4

Apart from @ChrisDown answer, here is another approach: bypass directories

With this approach, you can :

vi ./*

and it will start vi on all the files in the current directory even if it contains subdirs, bypassing those subdirs

vi() {
  for arg do
    [ -d "$arg" ] || set -- "$@" "$arg"
    shift
  done
  [ "$#" -gt 0 ] && command vi "$@"
}

This one just do vi, on any argument that are not directories... Hence it won't teach you to use "vi" for "cd" ;)

And it will not call vi if you just did: vi somedirectory (ie, mistyped vi instead of cd). But it will not cd there automatically then, so you still remember you have to type cd ^^

I used a "compatible" way to change the arguments lists, so that it's portable to many platforms.

3
  • 1
    note: command something : starts the "something" command (ie, the first occurence of "something" found using $PATH) instead of any alias OR function named "something". \something would only bypasses the alias, but would still the function if it existed (and here, that would mean the function "vi" would call itself, and loop). Commented Jan 16, 2014 at 9:55
  • @ChrisDown: we are talking an aid to a user, which I hope won't try to hack himself ^^ . And that eval is to set a new set of arguments (set -- ... ), so it's less dangerous in itself Commented Jan 16, 2014 at 10:01
  • @StephaneChazelas: thanks for the edit! I tried to write it that way, but I was worried about looping infinitely [I trust you it won't loop, though!. The 'for arg' is being evaluated before the inner treatment starts, and therefore its "$@" list is 'saved' and iterated over, and not changed even though the inner treatment changes "$@" ?] Commented Jan 16, 2014 at 10:15
1

One solution is to stop using cd altogether. Put shopt -s autocd in your .bashrc or setopt autocd in your .zshrc. Then to change to a different directory, type the directory name, without any command.

Don't forget to type vi if you want to edit a file.

If you really want a single command to either change to a directory or edit a file, you can make it a function:

vi () {
  if [ $# -eq 1 ] && [ -d "$1" ]; then
    cd -- "$1"
  else
    command vi "$@"
  fi
}
-6

Use alias feature in Unix. Once you alias cd to vi, the problem will be resolved.

5
  • 5
    ...this would mean that one cannot use vi without manually overriding the alias, which seems highly undesirable.
    – Chris Down
    Commented Jan 16, 2014 at 9:58
  • 3
    This answer comes across as slightly trollish. It does answer the original question, as the OP did not specify they ever needed vi on a file. The answer, although somewhat fun, is certainly not useful.
    – gerrit
    Commented Jan 16, 2014 at 9:59
  • 1
    @ChrisDown Or this would teach you to use the proper vim instead.
    – Kevin
    Commented Jan 16, 2014 at 19:00
  • @Kevin vim is not more "proper" than vi -- on many systems, vi is all that is available.
    – Chris Down
    Commented Jan 21, 2014 at 3:28
  • 1
    @ChrisDown I'd argue it's better to know what to expect. If you expect to use vim features, use vim. If it's not available, use vi and expect the more limited feature set.
    – Kevin
    Commented Jan 21, 2014 at 3:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .