Customizing Bash Terminal


 A custom terminal is a great way to subtelty express yourself while also having fun as you use it to gather data, run or install programs, debug, code, or just parse files. One fantastic option is to download a popular terminal theme. This option will have better support and functionality. However, it might be loaded with features that can be distracting, and it isn't necessarily unique. That is A-OK, perfectly respectable. But maybe that isn't for everyone.

I care about aesthetics when determining which products I buy, the clothes I wear, how I design a room in my apartment, and naturally how my terminal/IDE themes look. It sounds superficial, but certain looks just bring joy into my life. 'Tidying Up with Marie Kondo' helped me realize that I only want to keep or use things that spark joy. This led me down a big rabbit hole to explore how I could design my own terminal. Here, I will show you some of the things I have learned to hopefully help you customize your own terminal.

I use iTerm2, specifically using the bash shell, just for simplicity. It makes things easy if I want to update a linux or unix terminal, since I like to alternate. You can use any terminal you prefer.

Editing terminal settings

 First and foremost, edit your terminal's background color, text color, fonts, settings, etc. This doesn't require any programming, but it is good to knock this out first since it will be the foundation we build upon. At minimum, changing the text and background color to suit your style helps when editing later sections. Things like fonts, spacing settings, background image, and transparency can be updated at any time you prefer.

In iTerm2, simply navigate to Preferences -> Profiles. Create a new profile (if desired). Then, select Colors. There are many presets to view and select, or you can edit each preference individually. Next, you can select Text to change and font settings such as font type, font size, the blinking cursor, etc. Explore other tabs and see if there are any other desired settings you may want.

Adding colors when listing files

 Next, we start the fun stuff. If you type ls, the output will be in a single static color that you have set up in the earlier section. Let's update this to make it easier to read.

Open your bash_profile. This is typically found in ~/.bash_profile. If you do not see it, create one by typing touch ~/.bash_profile. Then, open it using your favorite text editor. We are going to paste this:

export CLICOLOR=1
export LSCOLORS=exfxcxdxbxegedabagacad
(or LSCOLORS=di=34:ln=35:so=32:pi=33:ex=31:bd=34 on Linux)

CLICOLOR=1 sets the environment variable to enable colors in the command line. This is used on FreeBSD or MacOS systems. The compliment to linux systems can be set using the dircolors command. LSCOLORS=... is optional, but it sets the environment variable to specify which colors/backgrounds/boldening to be used for types of files displayed using ls.

Before continuing, I would like to share this useful website I found: LSCOLORS GENERATOR. This page can help you identify what colors you want displayed for the specified filetypes. In short, the string after LSCOLORS can be broken down 2 characters at a time. Let's take the first two in the example: ex. It's position is at the front of the string, so it refers to directory file types. e refers to the not-bold color blue, and x refers to no background color. If any colors are capitalized, then they are boldened.

Simply update theLSCOLORS variable to display the colors you'd like. After saving, either restart your terminal or run this command to apply the changes: source ~/.bash_profile. Then, type ls and you will be able to see file types listed in color!

Updating the PS1 environment variable

 There are a tremendous amount of ways to edit the prompt statement, so I will just highlight some of the info I have learned. The default MacOS $PS1 is: PS1='\h:\W \u\$'

  • \h is the hostname
  • \W is is the basename of the current working directory.
  • \u is the current username

We can add colors, other prompt characters, or even emojis. To add colors, this involves adding non-printing sequence characters. \[ and \] are the beginning and ending sequence characters. For example, to edit the default $PS1 variable to have the username display in red, it would be: PS1='\h:\W \[\e[31m\]\u\[\e[0m\]\$'

This would appear as such:

To add other prompt characters or use different colors, try checking out this list here.

Emojis and other characters can also be included. Simply copy your favorite emoji (Mine is: 🦊) or other symbol such as . The symbols can even change color according to the color sequence characters above.

Adding Github branch to prompt

 First, you will need to have git installed on your computer. If you have homebrew, simply run the following command:

brew install git

You can also verify it is installed by running

git --version

Next, in your .bash_profile, add this function to the top of the file:

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


Then, in your $PS1 variable, wherever you'd like (I typically see it near/at the end) add \$(parse_git_branch). This variable will remain invisible unless you are inside a folder that has a currently checked out branch for the project you are working on.

As an example, this updates $PS1 environment variable contains the host ane basename of working directory, our username in red, and our github branch in blue:

PS1='\h:\W \[\e[31m\]\u\[\e[0m\] \[\e[34m\]$(parse_git_branch)\[\e[0m\]'

Adding an Alias

 Aliases are shortcuts to performing various commands. They can be used for any functional command you use commonly. For example, take the following alias to get complete info about the files in a directory:

alias ll='ls -laFh'

  • -la is to long list all files in directory
  • -F is to display a / after file directories
  • -h when used with -l is used to display an abbreviated prefix after file size (B for Btye, KB for Kilobyte, etc.)

Combining all of this, we now have customized our own terminal from scratch. Feel free to build upon this further, adding aliases, port over your functions, or share it. When making changes of to your own, I recommend keeping a backup. If you do not have one, at this point I quickly recommend performing something such as:

touch ~/.bash_profile ~/.bash_profile-backup

Congratulations, you have created a profile and customed your own terminal! If you didn't follow along but wish you had, here is a Github link to checkout or download the example .bash_profile! Happy Coding!

Post Number: #2

Radix Sort (LSD): An Overview


  Learning doesn't end after school. Learning is a life-long endeavor. In college, the Algorithms class I took went over some of the beginning concepts of algorithms, how they work, big O notation, and strategies for picking an algorithm to solve a problem. Things such as Merge Sort, Quick Sort, Insertion Sort, and Heap Sort, to name a few. Of these sorting methods, one limitation is that the fastest they can sort an array of numbers is O(n * log(n)). What if we needed to sort an array in a linear time complexity?

Radix Sort (Also known as Bucket Sort) can accomplish this. It sorts the numbers in the array into buckets, labelled 0 through 9, based on the value of each individual digit. Then, it repeats this process until the array is fully sorted. There are 2 types of Radix Sort: LSD and MSD.

LSD refers to sorting the array starting from the least significant digit. Similarly, MSD refers to sorting the array starting from the most significant digit. This post will only be referring to the LSD version of Radix Sort and any code will be written in Ruby.

There are 3 concepts to this function we need to put together first before we can create our radixSort algorithm. First, we need a way to find out the length of the numbers. Second, we will iterate through the array to find the maximum length. And third, we need a way to obtain the specific digits of a number at any index.

Find the Length of a Number

 The goal is to obtain the longest number in the array, since that is how many times we will need to put numbers into buckets. This can be easily defined as follows:

def countDigit(num)
 return 1 if num == 0
 return Math.log(num.abs, 10).round(14).floor + 1
end

The idea is simple: Return 1 if num == 0 because 0 is only 1 digit long, otherwise we will calculate the length of the number. To calculate, we find the common logarithm of that number, round up to the 14th digit floating point place, round the number down and add +1. Therefore, this will then return the length of that number.

NOTE: I specified round(14) because there exists rounding errors when performing floating point decimal math. If you want to check this out, remove round(14) from the method above and try running something like: print countDigit(1000). In our case, round(14) is sufficient because we are only caluclating the common logarithm. Other types of floating point decimal math may require other logic. This is a separate topic that I encourate you to research if you're unfamiliar.

Iterate...

 Second, we will iterate through the numbers array while using the countDigit function to find the length of the longest number. We will create a new function for this, as it will get called in our radixSort method. This should be straightforward:

def maxDigit(array)
 maxNum = 0

 array.each_with_index do |num, i|
  maxNum = [maxNum, countDigit(num)].max
 end

 return maxNum
end

With these two functions, we are now able to grab the maximum length of all numbers in the array. This returns an Integer which corresponds to the maximum number of times we will need to sort the individual numbers into buckets.

Obtain Digit at Specified Index

 The length of the longest number found using the functions above corresponds to how many times we need to sort the array of numbers into buckets. Since we need to loop 'N' times, N being the length of the longest number, we will need to create a way to obtain the exact digit of a number at the specified index at the current loop value.

For example, say we have this array: [102,199,325,711,240,669]. The longest length of the numbers is '3'. In LSD Radix Sort, we begin looking at the last number for each of the numbers in the array and sort them into a bucket array. The bucket array is an array of arrays that is of length 10 (corresponding to the values 0-9). We then take that bucket array containing the numbers sorted by last digit and sort again looking only at the middle digit of each number. Lastly, we will sort that bucket array yet again, but looking at the first digit.

Essentially, we need a function that can take a number and an index, which returns the digit of the number at that index: number[index]

One way is to can convert the number from an integer to a string stringNum. Since we are looking at each digit from end to beginning, we can calculate the currentIndex by subtracting stringNum.length - 1 - index. Therefore, if a value exists at stringNum[currentIndex] we will return it, otherwise we return 0. We will also need to verify that the value of currentIndex greater than OR equal to 0 to correctly obtain all digits for the given number. If the currentIndex is less than 0, we return 0 since there won't exist a digit for that index. We can write our function as follows:

def getDigit(num, index)
 stringNum = num.abs.to_s
 currentIndex = stringNum.length - 1 - index

 return stringNum[currentIndex] && currentIndex >= 0 ? stringNum[currentIndex].to_i : 0
end

Combining to Form Radix Sort

 The only thing left to do is to define our radixSort method, combining the methods above.

First, we need to obtain the longest digit i in the given array and loop that many times. This loop I will call maxDigitLength. Inside this loop, we will define our bucketArray. Also, we will iterate through the supplied array of values.

Then, for each index of values j, we will use getDigit to obtain the digit at the current iteration of i. Based on the digit found, we will save the full number into the corresponding bucket.

After we are done iterating through the supplied numbers array, we will flatten the bucketArray to change it from an array of array to just an array. Additionally, we will update our supplied array to be the flattened and partially sorted bucket array. We repeat this process i times until our array is completely sorted. Our radixSort method should look something like this:

def radixSort(array)
 maxDigitLength = maxDigit(array)

 maxDigitLength.times do |i|

  bucketArray = Array.new(10)

  array.length.times do |j|
   lastDigit = getDigit(array[j], i)
   bucketArray[lastDigit] ||= []
   bucketArray[lastDigit] << array[j]
  end

  array = bucketArray.compact.flatten
 end

 return array
end

Big O Notation

 What is the time complexity of Radix Sort?

If we look at the radixSort method, the first loop is based on the largest length of the numbers in the supplied array, which I will call d. Inside that loop, we are performing a bucket sort. This sub-sorting algorithm has a Time Complexity of O(n + b), where b is the log base or the number of buckets and n is the length of the supplied array. Therefore, the Time Complexity of radixSort is a linear time complexity of O(d * (n + b)).

Worst Time Complexity would exist if there is one number that has a large amount of digits compared to the rest. In this case, our Time Complexity would be O(logb(max) * (n + b)).

Best Time Complexity would exist if all of the numbers are the exact same size: O(d * n)

Space Complexity is O(n + b). The base doesn't depend on the number of elements. If using a larger base, the sorting speed could increase, but it would take a significant amount of memory.

Fun Facts

  • Radix Sort method makes no comparison of elements.
  • The sorting method is stable. It avoids comparison by putting elements into elements.
  • Radix Sort is useful for sorting things lexicographically, such as string or numbers.
  • This is my favorite sorting method.

Please enjoy this video visualizing radix sort
I recommend having sound on!

Here is the Github link to checkout or download this version of Radix Sort!

Post Number: #1