Bash – Automatically open text files in editor instead of attempting to run them

bashshellzsh

When I accidentally type the name of a text file without some kind of editor command, and the text file is not a shell script, I get a "permission denied" error*, since the file is not executable, and the first token in the command line is taken to be the command to execute.

However, invariably this just means that I've inadvertently forgotten to type my editor command, so it would be convenient if the shell could somehow recognize that the first token is an extant text file without the "execute" bit set and automatically open it with either $EDITOR or $VISUAL.

Is there a way to accomplish this in Bash or Zsh? (I use Bash but am thinking of switching anyway.) It would be a little like Bash's autocd option, which automatically detects whether the first token is a directory and attempts to cd into it rather than giving the standard "Is a directory" error.

Ideally, if I give a list of files (e.g. with a glob) or any other set of arguments, all of these arguments would be passed to the editor command.

* Of course I can also get a "command not found" error if I'm specifying a file in the current directory without ./.

Best Answer

In zsh, as long as your text files have a file name extension (file.ext), you can work with suffix aliases. They are defined by alias -s name=value and are run as value text.name anytime the first word on the command line matches text.name where text is any non-empty string.

For example:

If you define

alias -s txt=vim

then typing

$ foo.txt

on the command line will run

vim foo.txt

This works for anything matching ?*.txt, even words with wildcards:

$ *.txt

will run

vim *.txt

It also checks only on the first word of the command, but will pass the whole command line as argument, even if there are suffix aliases for the other words:

$ foo.txt bar.c baz.vim

will run

vim foo.txt bar.c baz.vim

Important: This also affects any command with a matching extension, including those in PATH. Should you, for example, set

alias -s sh=vim

and you have a command named something.sh and you want to run

something.sh -p1 -p2 arg1 arg2

it would instead run

vim something.sh -p1 -p2 arg1 arg2

To disable this feature for one command, just prepend the command builtin:

command something.sh -p1 -p2 arg1 arg2

The obvious drawbacks are:

  • it works only on files with a file name extension
  • you have to define the alias explicitly for every extension

On the plus side:

  • it works only on files with a file name extension, so most executables in /bin and /usr/bin are save from being replaced by an alias.
  • you can define a (different) alias for any extension, so *.jpg or *.o files will not suddenly be opened with vim
Related Question