Terminal tricks to boost productivity

 Escape tedious commands

There’s always those horrible, tedious, uncomfortable to type commands that you type in every single day at work at least once. Something like

git pull or git fetch

Can be shortened to a much shorter command like gp or gf. Here’s where alias comes to the rescue. But before that, we need yo identify what long commands we type in more often to make the most out of our aliases.

 Identifying long commands

To see the commands that we use the most we can call the history command and with the help of superuser, make sense of our daily input.

history | awk '{CMD[$2]++;count++;}END { for (a in CMD)print CMD[a] " " CMD[a]/count*100 "% " a;}' | grep -v "./" | column -c3 -s " " -t | sort -nr | nl |  head -n10

The output of that command was the following when I typed it in my computer:

     1  2009  20.092%    git
     2  1058  10.5811%   docker
     3  802   8.0208%    make
     4  407   4.07041%   ll
     5  383   3.83038%   cd
     6  350   3.50035%   kubectl
     7  178   1.78018%   ls
     8  151   1.51015%   rm
     9  151   1.51015%   aws
    10  148   1.48015%   crafter

If I do the same changing the $2 for $3 then I get the next positional command:

history | awk '{CMD[$3]++;count++;}END { for (a in CMD)print CMD[a] " " CMD[a]/count*100 "% " a;}' | grep -v "./" | column -c3 -s " " -t | sort -nr | nl |  head -n13
     1  694  6.94069%
     2  650  6.50065%   commit
     3  408  4.08041%   status
     4  311  3.11031%   ps
     5  262  2.62026%   ssh
     6  209  2.09021%   logs
     7  203  2.0302%    get
     8  175  1.75018%   |
     9  172  1.72017%   add
    10  171  1.71017%   checkout

From issuing those two commands, we’re able to extract a few conclusions:

So, for now on, we will focus on 2 out of the 3 most commonly used; git and docker.

 Creating alias

Next up, create the actual aliases, but before that let’s decide on an appropriate name for the resulting command that we’ll create. If we take a look to the most used command we’ll want to create something meaningful to be able to identify what that alias does, but also make it short to improve our performance.

For example the combination of git commit -m <message>. I do this 5 to 10 times a day on the least git intensive day of them all.

$ alias gcm='git commit -m'
$ gcm "First commit" .
$ git push

That will create our alias and set it up for our current session, also the amount of characters required to form the command went from 13 to 3, pretty big improvement I would say.

Now, let’s also poweruser our Docker command and create some aliases to it. There’s one thing that I do a lot these days, that being a temporary Alpine Linux containers to test stuff. After which, the stopped container is not needed for any reason, unless that’s gathering dust and occupying disk space. The command itself is a bit awkward to type in: docker run --rm -ti alpine sh. That grants me an interactive container to play with, which is how I create most of my Docker images.

$ alias alpine-shell='docker run --rm -ti alpine sh'
$ alpine-shell
/ #

We have another massive character reduction right there. What about killing all the running containers, and removing them? I’m also going to create an alias for that docker kill all functionality

$ alias dka='docker kill $(docker ps -q)'
$ dka
e94423e8d2e7

I also like to have all the containers that are stopped removed from my machine, furthermore, we don’t need the volumes associated with the removed containers laying around doing absolutely nothing, remove those too. I’ll call it docker remove stopped

$ alias drms='docker rm -v $(docker ps -aqf "status=exited")'
$ drms
e94423e8d2e7

Now, I love automation, and because of that I want to concatenate my 2 commands into 1 single easy to type command: dclean which stands for docker clean. To test this command out, we’re going to generate a few containers to kill and remove:

$ for c in $(seq 5); do docker run -d alpine sleep 100; done
0eb093472f56aa26c85b91449d733a40ca94d8bf09cfbf496a2d6632da53bf19
fc1800580212a5468506298d21add15700b904ac3067fd5001e6cb171c6a341e
da7aaa55bcce6d1bedd09157075105576eadb8c6ea05cf268068951a064e4c06
07706331a5072436dcd4bcc842547925227f912301d37027126305eaf9abe67b
7d15e9f9bced2a4beb600617141ee31515730e6a4c3e8524530754ce88e05c06
$ alias dclean='dka; drms'
$ dclean
7d15e9f9bced
07706331a507
da7aaa55bcce
fc1800580212
0eb093472f56
7d15e9f9bced
07706331a507
da7aaa55bcce
fc1800580212
0eb093472f56

I’m already seeing few more minutes added to my day by just adding 5 silly aliases, but useful nonetheless.

Did you think we were finished? No way, we’re just getting started

 Going the extra mile with functions

At this point you should have a clear understanding of what aliases can do, but not what they cannot do, imagine that you want to create an alias that concatenates two commands, but needs a part in the middle of the command to be dynamic.

git commit -m "<message" && git push

Unfortunately alias cannot make that happen for you but, luckily enough I know just the right approach to use, did I say functions? I think I already did.

$ function gcmp() {
  git commit -m "${*}" && git push
}
$ gcmp Remove comment

You need a passphrase to unlock the secret key for
user: "Marc Lopez <marc5.12@outlook.com>"
4096-bit RSA key, ID F543AAF5, created 2016-05-18

[master 3bee85a] Remove comment
 1 file changed, 1 deletion(-)
Counting objects: 7, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (7/7), 1.38 KiB | 0 bytes/s, done.
Total 7 (delta 3), reused 0 (delta 0)
To git@github.com:marclop/docker-alpine-images.git
   eba5d6d..13420ee  master -> master

For those unfamiliar with ${*}, it takes everything typed after gcmp and passes it to the function, so it’ll fill fhe message part.

Also, we can improve readability of commands aliases and instead of concatenating 2 commands inside an alias, the same can be done with a function and let me say this, it looks much better.

function dclean() {
  docker kill $(docker ps -q)
  docker rm -v $(docker ps -aqf "status=exited")
}

Another function I have available in my terminal is to check GitHub status, if systems are operating normally then it just tells me that all the system’s are in great shape, if not, it will print the last github message regarding their current incident. Be aware that the script uses jq. Installing it on Mac OS X is as easy as typing brew install jq

function github_status() {
  local STATUS=$(curl -sq https://status.github.com/api/status.json | jq .status | tr -d '"')

  if [[ ${STATUS} == "good" ]]; then
    echo "All systems are in good shape"
  else
    MESSAGE=$(curl -sq https://status.github.com/api/last-message.json | jq .body)
    echo Last message from github is: ${MESSAGE}
  fi
}

To finalize this chapter, remember to save all this functions in the appropriate .bash_profile / .bashrc / .zshrc inside your home directory to have them load up when starting up the terminal. As a rule I always have separate files for aliases or functions and source that file inside my shell, which is zsh when I’m using my laptop.

 Install and Set up zsh

You might ask, why the hell should I switch my default shell from bash to zsh? It’s quite easy to answer the question from my side:

Installing it is as easy as typing

$ sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

That will set it up for you, if you want more information on how to set up the fonts and all the other stuff, here’s the link. Here’s an example of a auto competition with a git command and a git directory with non-committed staged changes
git-completion.png

git status.png

 Wrapping up

As you can see, following a simple set of instructions can boost your productivity a lot by cutting the type in time for most annoying commands by at least half. To close the article here are some useful bullet points:

If you liked this blog post, click on recommend below or follow me on Twitter

 
0
Kudos
 
0
Kudos

Now read this

Road to Continuous Integration

Introduction About a year ago, I had some doubts about Continuous Integration because of how I had seen it working and some of the challenges that this methodology presents, Thereby I wanted to take a better approach at it in my new... Continue →