Is there any shell/shellscript which identifies that there is already an alias for the command I have typed on the command line.

Eg

On shell I type

git checkout master

Shell prints "You can use alias you have for that : gcm"

Then Shell proceeds with checking out master like normal.

I am aware of the alias command which lists all the available aliases. I want shell to remind me to use alias when I am not using them and typing out the full command.

  • 1
    Which shell do you use? – Gilles Apr 29 '15 at 23:10
  • Zsh. But I don't mind answer with other she'll. – Vishwanath Apr 30 '15 at 2:56
  • It might take a bit of coding, but, at least conceptually, it wouldn't be too hard to write a script which greps the output of the alias command for its first few arguments (the command to be executed), prints a reminder if it gets a match, and then runs its arguments with an eval. The tricky part would be that if the command to be executed runs in a subshell, its side effects would be lost to the calling shell. Built-ins might also be a problem. So, a basic implementation would be pretty easy, but one that actually works correctly, would be more difficult. – Joe May 3 '15 at 2:19
  • It would be a stretch, but if something like this was implemented as part of an AutoKey macro, the macro could then emit the original command as if the user had retyped it. That might work - eliminating the problems from the previous comment. While this might be instructive, you wouldn't want to leave anything like this running on a regular basis. It would be more of a diagnostic/educational tool for the operator. – Joe May 3 '15 at 2:30
  • 1
    this srot of featture would probably have to be compiled into your shell.it would have to run before alias substitution – Jasen May 3 '15 at 11:46
up vote 6 down vote accepted
+50

Here's a conceptual approach that might work.

The alias command generates a list of all aliases, each followed by an = and it's definition. This output could be parsed by extracting the alias name from between the first blank and the first =. Everything after the first = would be the definition to be matched against. This sounds like something easily handled using associative arrays in awk.

Two complications to this (that I see):

1) Since the definition can consist of multiple words, you'd have to do something like measuring the length of the definition minus any enclosing quotes and limit your compare against the entered command to that length.

2) Aliases can hold some weird stuff. Here's my weirdest one (and I'm sure they can get a lot weirder):

alias pqp='cd ~/pq;[ -n "$(ls)" ] && mprb * || echo "Print Queue Empty"'

The point here is that aliases can contain (almost?) all the special characters the shell wants to interpret and expand, so it would be best to code this in something else like awk or Python where the two strings you need to compare will be treated as simple character strings.

The next issue is that you want to actually run the command after you're done matching and issuing any messages.

The concern here would be that anything you run from within your program, even if it's just another script, will (normally) be executed in a child process. This means that any (shell-level) side effects of the command will be lost when the command terminates and the subshell closes. The most obvious thing is the return code, $?, which you would have to capture and reissue as the return code of your utility.

If the alias included an invocation using the source, . command, then you'd be pretty much out of luck because running that in a subshell would completely cancel the intended side effects.

Shells contain a number of built-in commands like cd. Some of these have equivalent programs as does [ and /usr/bin/test, but some, like cd don't and, even for those which do, the built-in versions don't always have the identical behavior and options that the external ones do.

The above problems exist because the final command is coming from somewhere other than the standard input of the current shell level and is processed differently because of that. This is where something like AutoKey may be able to help.

AutoKey is a macro processor which can be used to automate various actions in an X (gui) environment. In this context, it could be used to invoke a macro when you press a user defined hotkey. The macro could read and analyse a command line you would type into it, issue any messages (about aliases, etc.), and then retype the command as if you typed it on your keyboard.

The advantage here is that Linux (really your desktop environment/terminal emulator) can't tell it's not you typing the command and everything proceeds in your original, native environment as if AutoKey wasn't there at all.

A second advantage of this approach is that if you just enter a command without first pressing the hotkey, it's business as usual with no overhead, etc.

This bring me to a final point which has been discussed at length in various places on stackexchange and elsewhere.

It's almost always a bad idea to take a normal part of any system and change how it works by default under the hood without that being totally visible to the user (you, in this case).

In brief, if you customize a system to behave in a non-standard way, there are two major consequences.

1) If someone else uses the system (e.g. to help you debug a problem), they will encounter unexpected results which could have any number of unpleasant consequences.

2) You become accustomed to the modified behavior and then (unconsciously) expect it to work when you are using another system which has not been customized in the same way.

The classic example of this is defining an alias such as

alias rm='rm -i'

This sounds like a great idea until you type rm on another system and the files are immediately deleted when you were expecting to be prompted first.

The way around this is something like:

alias rmi='rm -i'

If you type it, it works, but if you type it on another system, it probably won't do anything other than issue a command not found error.

This is particularly important in the middle of the night when something important is broken, you're not as alert as you'd like to be, and you're under pressure to fix it now. That's when you really don't want any unexpected behaviors or things you have to waste time explaining to people.

It works the same way with doing alias checking with an AutoKey macro activated by a hotkey. If you don't go out of your way to activate the macro by pressing a hotkey, then everything works as anyone would expect it to. A properly chosen hotkey probably won't be pressed by accident and, if pressed on another system by habit, probably won't do anything harmful.

  • I didnt get enought time to go throuh the solution completely but accepting and rewarding this answer since it got many upvotes...Will try and update when I can. – Vishwanath May 8 '15 at 4:55
  • bash also has a read command which may be used to get input which is not subjected to any of it's many expansions. It may be possible to use that instead of an external program such as AutoKey, but it can get fairly tricky because using what you have read in can often expose part or all of it to expansions. – Joe May 8 '15 at 23:53

I have a solution in bash. You need a function that is exectued before every command. Since bash doesn't support that natively you have to work around that using the DEBUG trap.

See the bash's manual page part of the DEBUG trap:

If a sigspec is DEBUG, the command arg is executed before every simple command, for command, case command, select command, every arithmetic for command, and before the first command executes in a shell function

So the function could look like this (the first part is copied from that superuser answer):

preexec () {
  [ -n "$COMP_LINE" ] && return  # do nothing if completing
  [ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return # don't cause a preexec for $PROMPT_COMMAND
  local this_command=$(HISTTIMEFORMAT= history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//")
  # check if the command occures as an alias
  a=$(alias | grep -F "='""$this_command""'" | grep -oP '(?<=alias\ )[^=]+')
  # if yes, print a notice
  [ -n "$a" ] && echo -e "You can use an alias you have for that: \033[01;32m$a\033[00m"
}
trap 'preexec' DEBUG

When typing:

$ git checkout master

It prints:

You can use an alias you have for that: gcm

and then comtinues with the command.

  • That looks really interesting! However, man bash says ALIASES Aliases allow a string to be substituted for a word when it is used as the first word of a simple command. which means there can be other stuff after the alias on the command line. If I read your code correctly, it would fail to match an alias for a command line with anything after the alias. So, the approach is great, but it may need some additional code to make sure you're just matching the alias and not the whole line. – Joe May 7 '15 at 8:28

Found this while researching more on what I wanted.

For zsh there is a plugin alias-tips which already does this.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.