3

I am trying to figure out how to add new runtime flags to commands that are run from the terminal.

For eg. : I have recently started experimenting with Docker and find it tedious to clean up exited containers by copy pasting IDs. I want to add a command line option clean to the docker runtime, so that when I run docker clean (or perhaps docker --clean if we're going that way) I can internally map it to run a cleanup command with already supported options by the docker runtime (namely docker rm $(docker ps -a -q -f status=exited)) Is it possible to establish such a mapping?

I know one option is to use aliases, however aliases don't allow for having spaces / command line flags in the alias names, to the best of my knowledge. Similarly, shell functions don't help because they override the entire functionality (or perhaps I'm doing it wrong). I have wanted to explore this possibility for a while, so any help will be appreciated.

fwx
  • 173

1 Answers1

4

You can define a bash function with the same name as an executable, and have it process your additional parameter and call the original function unambiguously using the command builtin. From man bash:

command [-pVv] command [arg ...]
       Run  command  with  args  suppressing  the normal shell function
       lookup. Only builtin commands or commands found in the PATH  are
       executed.

To illustrate,

function ls() { 
  case "$1" in 
    "foo")  shift
            echo "do new thing with remaining args: $@" 
            ;; 
    *)      command ls "$@"
            ;;
  esac
}

Then

$ ls -ltr --color=always
total 12
drwxrwxr-x 2 steeldriver steeldriver 4096 Sep 17 08:16 subdir1
drwxrwxr-x 2 steeldriver steeldriver 4096 Sep 17 08:17 subdir2
drwxrwxr-x 2 steeldriver steeldriver 4096 Sep 17 08:17 subdir3

works as normal, whereas

$ ls foo -ltr --color=always
do new thing with remaining args: -ltr --color=always

(you may need to unalias the ls command in order to try this out).

Obviously a real-world implementation should do proper error checking - perhaps using getopts to process the entire command line rather than a simple switch/case on $1.


Alternatively (and more traditionally) you could achieve the same by writing a wrapper script and placing it somewhere that comes earlier in your $PATH than the original executable (such as /usr/local/bin or $HOME/bin). Within the wrapper, refer to the original executable by its absolute path.

steeldriver
  • 136,215
  • 21
  • 243
  • 336
  • 1
    I took inspiration from (see man less) the LESS environment variable, and have grouped my favorite options in environment variables, so I do pstree $PSTREE ..., dmesg $DMESG, sudo less $LESS ..., and Profit! – waltinator Sep 19 '16 at 03:02