loading...
Cover image for Minimizing Keystrokes, Maximizing Productivity  -  Bash Scripting

Minimizing Keystrokes, Maximizing Productivity  -  Bash Scripting

akshansh2000 profile image Akshansh Bhanjana Updated on ・4 min read

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:

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?

git add .
git commit -m "long method"

How about reducing the above two steps to:

gc "short method"

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

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:

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?

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

Or perhaps managing your Python venv?

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

Want to go up a directory?

alias up='cd ..'

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

alias ls='ls -ACF'

Go ahead and experiment!


Functions

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

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.

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:

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:

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:

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:

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:

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?

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.

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:

user@pc:~$ 

If you prefer minimalism, add this to your .bashrc

export PS1="> "

Your terminal prompt should be changed to:

>

Too minimalistic? No problem.

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

which results in…

user in ~/Desktop
>

Let's add some colors to it.

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

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?

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

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!

Posted on by:

Discussion

pic
Editor guide
 

Very nice! I'm not much of a shell-scripter and have always found it quite annoying to write them because I do it so rarely. I wrote one to bootstrap a new machine and that was fun (sarcasm). I do, however, love old Unix utilities like awk and sed and would love to use them more for scripting and they're more portable and have less drift than writing Python or Ruby scripts.

The functions are nice! I never quite found a good way to move up multiple directories and do it quite often, but I do it far less now as I rely more on fzf globbing. I think functions have far more utility than aliases as I only keep a handful around and heavily rely on my history -- shameless plug: my post about efficiency in the terminal/shell

Do you have a link to your dotfiles or a repo with the functions that you use? Would love to check 'em out!

 

Hahaha, indeed, using the shell can sometimes be annoying. Moving up directories continuously is an example :P

I took a look at your post, and it's a great read! reverse-i-search is something I discovered quite late, and wished to have known about it sooner haha.

Sure, I have my dotFiles hosted on GitHub. Though I'd suggest that you look at the .zshrc instead of .bashrc, since I haven't updated the latter in quite a long time.

Thanks for reading!

 

Yeap! It's such a rare occurrence for me nowadays, because I literally just keep all the projects that I operate in open with tmux with their sessions auto-saved. They're restored on restarts. Tmux was something that took me a super long time to adopt (start of this year).

Yeah, I feel like reverse-i-search is not mentioned enough. It's spectacular with fzf integration: github.com/junegunn/fzf.

Neat neat! I like that function you've got for git branch, current working directory, and more. You've even got some perl in there. LOL! Wow! Out of curiosity, how did you go about learning all that you know about shell-scripting?

Your .zshrc is so much cleaner LOL. You've even got functions to generate what appears to be checksums. You're probably the first person that I've seen with Dart-lang repos. I always like to ask C++ programmers about Rust -- have you tried it? Thoughts?

Ahh, I've never used tmux, but heard a lot of praise! I've been using i3wm for quite a while, and so I just open multiple terminal windows and pretend it's tmux haha. Anyway, I would surely give it a try, as the session-restoring sounds great (and time-saving)!

Looking at fzf, do you also use vim/emacs? I've never gotten around to using them, as I think that it'd take a lot of time to migrate from VSCode to a total keyboard experience, and so I keep postponing trying to learn the shortcuts :P

Haha thanks, I use perl majorly for applying regex into bash strings (like extracting the directory name, CPU Temp, etc.)

I learned all that majorly from other awesome people's articles online, and sometimes through books (e.g. O'Reilly's Learning the bash Shell).

Ahh yes, the checksums function is quite useful. It generates the checksum, checks it against the one you provided as an argument, and returns if the two match. So, for md5 checking, I can simply do

md5 <name_of_file> <given_md5_hash>
# true or false

So yes, I use it a lot :P

I majorly use Dart for mobile development i.e. Flutter. And Rust has been on my list for quite a while now, but never really got around to learning it. From what I've heard, people just call it a better C++ (if that's possible :P). I think I might start soon. Are you planning on learning it, too?

Yeah, I guess tmux is certainly more for a terminal-based workflow. I can't live without it. Switching windows is all keyboard shortcuts. I figure that i3wm is, too? I'm on macOS, and spent the last two hours looking at Yabai, a super popular tiling window manager for macOS

Yeap! You nailed it. I'm a total Vim-nut, but it's partially because I don't do any sort of dev in ecosystems that have amazing IDEs, like Java, iOS, etc. I try to keep a mouse-less workflow which comes in handy when having only a laptop (before the pandemic began). With regard to fzf, just navigating a filesystem is so much nicer. I use the globbing a lot!

$ cd ** # and I can just start typing the name of some directory that's nested levels deep 

$ rg --files | fzf # list the files in the current directory and fuzzy search / can also pipe ls into fzf, of course

My reverse-i-search becomes this w/ fzf (instead of the standard one-liner):

  2283    git diff -w
  2284    git status
  2285    git add README.md
  2286    git commit -m "UPDATE readme - with 'tools of the trade'"
  2287    git push
  2288    git add -A&&git commit --amend --no-edit
> 2289    git push --force-with-lease
  427/1043 +S
> git

Yeah, your checksum functions are friggen neat! I've saved them :)

Haha -- so I've never really done too much systems programming and reading C++ is pretty straight-forward to me (at least in relation to Leetcode problems). Well, the problem with C++ is the footguns with memory. Right? I think it was only last year or the year before that Google reported two zero-days in Chrome. A large organization with as many resources as they have, has made a valiant effort, but it is still a problem. And it seems like the bulk of CVEs are memory-related. I currently do a little bit of Go which is useful but I really don't like its lack of elegance, though simple, and maintainable. I like modern language facilities and constructs and tooling, vibrant community, but without the memory footguns of C++, which Rust seems to provide (which is also being used on my team at my current company). I plan on learning it, because I'd like to have a performant systems language in my toolbox

Yep, i3wm is also all-keyboard workflow. Honestly, I didn't even know how much time I spent alt+tabbing and moving between windows using my mouse until I started using i3wm. I guess I'd have a similar experience once I switch from VSCode to vim :P

I've heard about Yabai. Probably somewhere in unixporn (SFW), people have some amazing rices there.

Ahh yess, not using a mouse certainly helps with a laptop. Out of curiosity, which laptop do you use? I particularly love MacBook's touchpads (sometimes preferable over a mouse for me).

Wow, your reverse-i-search looks beautiful. Comparing to the one-liner I get hahaha, I'd perhaps try out fzf soon.

I literally just Googled "zero-days" right now :P
Yes, the main problems lie in memory management and garbage collection of C++ (which I believe Rust improves upon?)

The lack of generics in Go really annoyed me, although (finally) they're coming in the next version, so it might be a really interesting time to improve our GoLang skills.

Again, out of curiosity, how long have you been working with C++?

VSCode is so hard to switch from. I watch a lot of tech YouTubers and I'm like, "Wow! WTF! It's like a full-blown IDE!" I used to use SublimeText with its vim plugin before doing a complete switch after being comfortable with the keys and this was before there were so many super video tutorials from YouTubers, like The Primeagen's troll video before he created a six-part series on some basic and intermediate Vim: youtube.com/watch?v=1UXHsCT18wE. I hear that the vim plugin for VSC is pretty good, though!

LOL! I think you've just sold me on a tiling window manager. I'll probably install Yabai tomorrow if it's a light work day. I was not aware of that sub-Reddit either! Just joined. LOL.

I only have Macs -- my personal machine is a 2019 MacBook Air, but I started a new job in April and was provided a 15" MacBook Pro (late 2019). Yeah, the touchpad is nice, but still requires me to move off my keyboard. I even surf the web with Vim keybinding using the Vimium plugin in both Chrome and Firefox. I also have the keyboard shortcuts turned on in Gmail (which are also Vim keybinding). Vim-nut, I tell ya!

Here's a quick five minute video on the capabilities of fzf: youtube.com/watch?v=1a5NiMhqAR0. It is one of the most starred projects on GitHub for a reason and the Vim integration is phenomenal.

This was the Hacker News article discussion and article that was heavily upvoted a year ago - Serious Chrome zero-day. You'll see people ranting about the C++ right at the outset. Yeah, Rust has a very very strict compiler and introduces the "ownership" model along with semantics around it, dubbed "borrow-checking". The quality of the software, at least in open-source, in that community is pretty phenomenal. A few tools that I use are Rust-based now -- like my terminal emulator, Alacritty (perceptibly faster than iTerm2) and cross-platform (macOS and multiple Linux distros), ripgrep for searches (faster than ag and most certainly, grep).

Yeah, I saw a demo of generics in Go in the Golang sub-Reddit. I'm totally fine with or without it, because I don't envision writing more Go than I need to. It would be a welcome addition and reduce the SLOC in a big organization. However, I would much prefer to learn and work in Rust, as I find the language much more expressive (modern language features) even though there's a steep steep learning curve. My current company uses Go, but finds it difficult to get observability and runtime introspection without going whole hog into Google land with K8s and containers to layer over it.

Haha, funny that you ask. I've probably written no more than two programs in C++ (a small game and calculator). I've done some Leetcode problems in C++ and have read some C++ source code in open-source projects, but my entire career has been in the web-stack which I'm getting bored of, so I want to drop down lower fueling my intrigue with Rust :)

VSCode is literally an IDE in the package size of a big text editor :P
Moreover, its extension support is one of the major reasons people (including me) can't let go of VSCode.

Ahh, this series is nice. Thanks for sharing! This is a great way of moving to vim. The only thing I did before trying vim was vimtutor, which is nice, but still a little overwhelming for first time use. It'll grow on me slowly, I guess :)

Hahaha, so did you install Yabai? And yes, Macs are great. I just found out about the Vimium plugin and wow, you clearly do love vim :P

I use Gesturefy or CrxMouse to speed up my browsing, but that's about it. Gonna definitely try Vimium after learning vim haha.

Ahh, that definitely makes Rust something to try soon! Also, I saw Rust to be among the most loved languages on StackOverflow, so it definitely is a good sign for its future :)

I've been using alacritty for over 3 months now, and yes, it's really a no-nonsense and lightweight terminal. Moreover, I also use dmenu-rs which is a Rust-based dmenu, and functions just like the extremely amazing spotlight search of macOS.

I tried Competitive Coding with Go once, just for fun really (majorly to see performance differences compared to C++). The speed was amazing, but the code writing part was definitely a headache xD

That was majorly due to generics. Now, since their introduction, maybe I'd try it once again. I'm just looking for substitutes for Python (for CP). Basically, I mostly use C++ during CP, but when the question relies heavily on hashmaps and lists, I prefer Python (mostly due to its ease-of-implementation and O(1) key searching). However, Python sometimes exceeds the time limit due to being really, really slow. So, if GoLang can solve that for me, I'd happily use it.

Ohh, I really thought that you were into systems programming with C++ haha. That's nice. I'm just diving into kernel development now, so C/C++ are gonna be with me for a long time now :)

The "Two steps from VSCode to Vim" video, I'm literally laughing hahahah. Took me quite a while to understand the satire :P

This was a great video; thanks for sharing :D

Enjoy! I've left a lot of questions and comments on those videos. Haha. He's pretty entertaining. I mean, Vi key-bindings are everywhere! Navigating man-pages and tons other Unix utils... I can't be the only one. Vimium really doesn't take much to learn aside from the movement keys hjkl, gg (top of page), <shift>-g (bottom of page), then f and it marks anything that's a link with a letter or a sequence of keys to press to visit the link or open the link in new tab/window. This trips me up each time I'm on someone else's machine. Gesturefy is neat! I didn't even know about this. I do love Firefox containers and tree-style tab plugins, though!

Oh! I was not familiar with dmenu, but that is pretty neat! I may give it a whirl -- so many things to try. LOL.

Didn't end up installing Yabai -- was chatting w/ a coworker using it and he's like, yeah -- you gotta configure the keys first and I'm like, "okay, guess I'll wait!" I end up installing Rust instead and reading the book 🤷‍♂️ #priorities

Yah! Rust has been atop or near the top of that list for the last two or three years. It's got a lot of traction in the San Francisco Bay Area tech scene.

I always admire folks that do competitive programming. I follow quite a few on YouTube that you may be familiar with Erichto, William Lin, and Rachit Jain. Does Go's standard library have the data structures that you need for most problems? And did you find problems where you could use goroutines? C++ is pretty much the only language that I see used in CP, but of course, back in the day, there was Pascal. How often do you reach for heaps?

I've never really used any of the other Python VMs, but I can't even imagine someone using Python for CP. It's the language I typically end up using for interviews, but it's not like my solution is being compared one implemented in another language -- just need to be able to bring down the algo complexities (not always easy for a non-competitive programmer)

Haha -- people at work ask me why, too. Just curiosity and the possibility of working on some hardware that I had no interest in years ago. I think reading about Discord's use of Elixir and Go, then switching from Go to Rust here, really sparked my interest. I also had a coworker at a previous company that was a huge Rust open source contributor before it was popular -- he wrote a bunch of device drivers and software for cameras and lights around his house and I found that really cool. It wasn't something I could particularly do.

So I ended up installing the Vimium extension, and, wow. I love it. You were right; it didn't take much time to get used to, but saves a whole lot of effort while browsing. Thanks for this!

Firefox's containers are indeed great. I never really used the tree style tabs, though, as I think I'd need a bigger screen (I pretty much always feel that my screen isn't big enough haha) and so I think I might try that later.

Hahaha, yes, Yabai, i3wm, dwm, and perhaps almost every tiling WM takes a lot of time setting up + getting used to. They do save a lot later, though. So, a worthy investment, I'd say.

You've sold me for Rust, really. Gotta start learning soon :P

I haven't heard about Erichto, but yes, William Lin and Rachit Jain are amazing. Go's standard library contains lists (obviously), trees, heaps, stacks and queues (easily implemented using slices), and some useful functions. It isn't as extensive as the C++ STL, but it still does a really good job.

About the goroutines, I never came around to using them, as I didn't even know that much programming when I used Go (I was in my freshman year :P)

Haha yes, Python for CP is usually frowned upon. Honestly, I figured that in competitions where the submission time matters (i.e. the time one took to solve the problem, and not the submission runtime), Python is really good!

When I became used to Python, I realized that I could sometimes solve a problem using Python in half the time it took to solve the same in C++. So, what I usually do is use Python for easy problems (so that I don't fall into TLE problems), and switch to C++ for the harder ones. I found this way to be really efficient! Moreover, when dealing with really large numbers, Python works like a charm.

Woah, Discord switching from Go to Rust is a really interesting step! Let's see how it fares in the future :D

 

Your cd function could be greatly simplified:

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

cd with no arguments already goes to the home folder. "$@" passes all arguments passed to the function exactly as they were passed. If there were none passed, it passes nothing.

 

Ahh, this looks great. It was a simple solution, really (should've been obvious to me). Perhaps, I spent a little too time thinking :P

Made the changes. Thanks!

 

Nice post!

A few small improvements ;)

  • Aliases and functions normally reside in .bash_aliases rather than the rc file.
  • gcc may clash with the widespread gnu gcc program which is run using the same command, perhaps gcd could serve the same purpose here
  • Aliasing in something that adds -a or . in git is not generally considered good practice due to the potential for unexpected results, adding and committing are very specifically separate commands. At best, users should be aware of the possible issues (which others on the internet have explained better than I could)
 

Thanks for the suggestions!

Yes, I believe putting the aliases and functions in a separate file would immensely clean up the rc files, so I'd be careful to do that from now.

As for the gcc, this never occurred to me as I never really used gcc apart from compiling cpp files with g++. Perhaps, I should add a little note in my post telling others to make sure that the aliases/functions do not try to override any other command :)

Ahh, I'll definitely read up about it; thanks for pointing this out :D

 

Using gcc for a function name is not a wise idea. Especially when you cope with C language. ;)

 

Thanks for the insight!

I realised this quite late 😅
I'll perhaps add a note in my post telling users to make sure not to name functions/aliases such that they override other commands :)

 

Nice writeup 🔥

Although a small suggestion

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

If you meant git add all the changes, than you should update it to git add -A
git add . will only stage changes in current directory, might get confusing if you run this in sub-directories.

 

Ahh yes, quite rightly pointed out. I'll update it in the post as well.

Thanks for reading!

 

Don't use git add ., use git add --all instead

Try basename.

url="https://github.com/akshansh2000/dotFiles.git"
git clone "$url"
cd "$(basename -s .git "$url")"

alias ..='cd ..'
alias ...='cd ../..'
 

I often use ctrl+r for history fuzzy search. alt+f to go forward a word, alt+b to go backward a word, etc. I recommend looking into readline's default bindings.

 

I'd surely do so. Thanks :)