Minimizing Keystrokes, Maximizing Productivity  -  Bash Scripting
Tags: bash, linux, beginners, productivity
Published: 2020-07-12 00:39:32

If you are more of a minimalist, perhaps terminals are your thing. To allow you to use your terminal to its full potential, let's learn a bit about *bash scripting*.

The tutorial has been divided into 3 parts:
- aliases
- functions
- customization

# Setting up
If you have macOS/Linux and use `bash/zsh`, you're good to go.

Before proceeding, make sure to have a `.bashrc` file present in your home directory. If not, you can create it by typing:

```bash
cd ~ && touch .bashrc
```
---

# Aliases
These are quite simple. Just like abbreviations.

What if you want to go up a directory? `cd ..`

What if you want to commit your changes? `git commit -m "this is long"`

All these commands can be vastly shortened by using *aliases*. Let's look at a couple of examples.

### Git aliases
What do we usually do after making some changes in a git repository?

```bash
git add .
git commit -m "long method"
```

How about reducing the above two steps to:

```bash
gc "short method"
```

It's quite simple, really. Add this line at the end of your `.bashrc` file:

```bash
alias gc='git add . && git commit -m'
```

**Note**: Make sure to not put any spaces (' ') between the `=` and the following/preceeding characters.

Now, open up a new terminal window, and try out your new tool.

You can probably figure out what everything means, here:
- `alias` is a keyword to define a new alias name
- `&&` is used to execute multiple commands in succession

Now, you can have something like:

```bash
alias gp='git push'
alias gu='git pull'
alias gs='git status'
```

Well, you get the idea.

### General aliases
How about remembering your most visited directories with simple names? Probably a folder where you store all your apps?

```bash
alias apps='cd ~/path/to/apps/folder'
```

Or perhaps managing your Python venv?

```bash
alias pyenv='python3 -m venv env'
alias startenv='source env/bin/activate'
alias pyget='pip3 install'
```

Want to go up a directory?

```bash
alias up='cd ..'
```

Always ls to show all the hidden files/directories as well?

```bash
alias ls='ls -ACF'
```

Go ahead and experiment!

---

# Functions
Remember the up alias? What if you want to go up 5 directories? Well,

```bash
up
up
up
up
up
```

can get really tiring. That's where functions come in.

Let's start off with an easy function. I can't possibly count the number of times I've followed my `cd` command with an `ls` command. Time to automate it.

```bash
function cd() {
  builtin cd "$@"
  ls
}
```

It might look confusing at first, but not for long. The `$` variable contains all the arguments provided to a function. Hence, `$1` is the first argument, `$2` is the second, and so forth. `$@` converts to all the arguments that were passed to the function. Also, `$#` returns the number of arguments provided. Well then, the pseudocode for the above:

```bash
function cd() {
  cd into the argument provided
  ls
}
```

And the `builtin`? Well, that is just so that the function call doesn't produce an infinite recursion. Something like:

```bash
function abc() {
  abc()
}
```

Try doing some `cd` now!

### up
Stepping up the game now, let's get back to the `up` function. For now, add this to the end of your `.bashrc` file:

```bash
function up() {
  if [ $# -eq 0 ]; then
    count=1
  else
    count="$1"
  fi
  
  i=0
  while [ $i -lt $count ]; do
    builtin cd '..'
    i=$((i+1))
  done

  ls
}
```

Fire up a new terminal session, navigate to some directory, and try doing `up 3` now. Interesting.

If you cannot make much sense of the code above, here's the pseudocode for you again:

```bash
function up() {
  if number of arguments is 0
    set count to 1
  else
    set count to the first argument

  loop from 0 to count
    go up 1 directory

  ls
}
```

### clone
How about cloning a git repository and navigating into it with a single command? Probably:

```bash
function gcl() {
  git clone "$1"
  
  repo_name=`echo "$1" | perl -nle 'm/([^\/]+(?=\.git))/; print $1'`

  cd $repo_name
}
```

Try `gcl https://github.com/akshansh2000/dotFiles.git` now!

**Note**: Make sure that a function/alias name doesn't override any other built-in commands, or you might end up having problems which are difficult to debug :P

### git everything
Executing a `git add`, `git commit`, and `git push` consecutively?

```bash
function gacp() {
  git add .
  git commit -m "$1"
  git push
}
```

Again, sky is the limit. You might end up creating some really useful functions!

---

# Customization (bash)
This is particularly for `bash` users. `zsh` has some really amazing themes, which you can check out [here](https://github.com/ohmyzsh/ohmyzsh/wiki/Themes).

Terminals are sometimes known to be ugly. They don't have to stay that way, though. If you have never customized your terminal, it probably looks like this:

```bash
user@pc:~$ 
```

If you prefer minimalism, add this to your `.bashrc`

```bash
export PS1="> "
```

Your terminal prompt should be changed to:

```bash
>
```

Too minimalistic? No problem.

```bash
export PS1="\u in \w\n> "
```

which results in…

```bash
user in ~/Desktop
>
```

Let's add some colors to it.

```bash
txtcyn='\[\e[0;96m\]'
txtred='\[\e[31m\]'
txtyel='\[\e[0;33m\]'
txtwhi='\[\e[37m\]'
txtblu='\[\e[34m\]'

export PS1="\n${txtblu}\u ${txtwhi}in ${txtyel}\w ${txtwhi}at ${txtred}\$(date +'%T')\n${txtcyn}> ${txtwhi}"
```

A bit better, perhaps?

![colored-terminal](https://i.imgur.com/lLN79vd.png)

Let's go one step further. How about displaying the current branch if you're in a git repository? And adding some bent pipe symbols at the starting?

```bash
txtcyn='\[\e[0;96m\]'
txtred='\[\e[31m\]'
txtyel='\[\e[0;33m\]'
txtwhi='\[\e[37m\]'
txtblu='\[\e[34m\]'

bold=$(tput bold)
normal=$(tput sgr0)

function gitBranch() {
    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
}

export PS1="\n${txtyel}┌─⭘ ${bold}\u ${normal}${txtwhi}in ${txtcyn}\w ${txtwhi}at ${txtblu}\$(date +'%T') ${txtred}\$(gitBranch)\n${txtwhi}└─⭘ "
```

It'd look something like:

![branched-terminal](https://i.imgur.com/uCTdcwH.png)

Well, there you have it. The basics of bash scripting.

All of my config files are available at https://github.com/akshansh2000/dotFiles, should you need them.

Happy reading!