2021-04-22


The World's Best .bashrc?

I like to do as much work as possible directly in my bash window/terminal.

"BuT pYtHoN iS sO cOoL!"

I know, I know. But when I'm trying to do science on a computer, the less I have to jump back and forth between different terminals/windows/screens/programs/languages, the better. (And you are using Linux if you're doing serious computational science [I'm writing this in 2021], so you're probably also using bash.) And, dispite having gotten a Ph.D. by staring at a computer, I don't like to type. My mantra is "type as little as possible." So, I have been collecting cool tips and tricks that make my simple bash terminal an absolute joy to work in.

Your .bashrc is basically just a set of commands that are executed every time you start a new bash window/terminal. If there are certain commands that you'd always like to run/be in effect when you work, adding them to the .bashrc saves you from having to type them in each time you sit at your computer. By adding snippets of code into your .bashrc file, you can seriously increase the speed and efficiency with which you're able to get things done and decrease the amount you have to type, all without ever leaving the comfort of your familiar, ugly bash screen. :)

Below is a version of the .bashrc file I use in my Terminal (Mac), HPC work, and any Linux system in general. (This version is slightly simplified by removing a few software-specific lines that you wouldn't need unless you were me anyway.)

For those of you who don't like to read, I've pasted the .bashrc code right here. (I still have hints and comment lines within the code if you genuinely do already know what you're doing and just need the reminders now and then.)

For those of you that would like to know why different parts of this code are cool, I've provided explanations of different sections below. (Don't get excited; my explanations are cursory. You need to already have a vague idea about these things to make good use of this page.)

The full code:

ulimit -s unlimited 2>/dev/null

ulimit -l unlimited 2>/dev/null


umask 0027 #Default settings for who can view/edit new files you create.


[ -z "$PS1" ] && return


WHITE='\[\033[1;37m\]'

export PS1="$WHITE<\u@\h:\w>$ "; #Use "\w" for full path, "\W" for current directory only.


## Color mapping for some Linux.

#LS_COLORS='no=00:fi=00:di=01;31:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31:*.i386.rpm=01;31:*.src.rpm=01;30:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.png=01;35:' ;

#export LS_COLORS


## COLOR MAPPING FOR BASH ON MAC OS.

## https://mkyong.com/mac/add-color-to-the-bash-terminal-in-mac-os-x/

export CLICOLOR=1

export LSCOLORS=GxFxCxDxBxegedabagaced


## Set the location of executables.

export PATH=$PATH:\

/Users/tryan1/scripts/:\


### Set any special location(s) of libraries required by special executables.

#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:\

#/lib64


## Shortcuts.

alias razor="ssh trr007@sample.computer.edu"

alias trestles="ssh trr007@dummy.hpc.edu"

alias pinnacle="ssh trr007@another.example.edu"

alias newcluster="ssh trr007@more.ddns.examples.edu"


if [[ $HOSTNAME = razor-l[123] ]] || [[ $HOSTNAME = compute???? ]]; then # WORKS FOR razor-l1 -l2 -l3 & COMPUTE NODES.

alias qi_raz12="qsub -I -l walltime=00:30:00 -q tiny12core -l nodes=1:ppn=12"

alias qi_raz16="qsub -I -l walltime=00:30:00 -q tiny16core -l nodes=1:ppn=16"

alias qi_raz01="qsub -I -l walltime=00:30:00 -q tiny16core -l nodes=1:ppn=1"

alias qi_block12='read arg; qsub -I -q tiny12core -l nodes=$arg:ppn=12'

alias qi_block16='read arg; qsub -I -q tiny16core -l nodes=$arg:ppn=16'

alias pjob='~/scripts/pbs_job_watch_razor.pl'

alias pque='~/scripts/pque_razor.awk'

alias wque='~/scripts/wque_razor.sh'

alias sapt='~/scripts/SAPT2016_razor'

alias baby='~/scripts/baby_sitter_razor.pl'

alias bqsub="~/scripts/batch_qsub.pl"

elif [[ $HOSTNAME = pinnacle-l? || $HOSTNAME = c???? ]]; then # RECOGNIZE IF ON THE PINNACLE CLUSTER. REQUIRES DOUBLE BRACKETS.

alias qi_comp04="srun -N 1 -n 4 --pty bash"

alias qi_comp16="srun -N 1 -n 16 --pty bash"

alias qi_comp32="srun -N 1 -n 32 --pty bash"

alias qi_condo32="srun -N 1 -n 32 --constraint fwang --pty bash"

alias qi_condo04="srun -N 1 -n 4 --constraint fwang --pty bash"

alias qi_condo01="srun -N 1 -n 1 --constraint fwang --pty bash"

alias bqsub="~/scripts/batch_sbatch.pl"

alias pjob="~/scripts/ahpcc_slurmjob_watcher.sh"

unset MANPATH

else # IF NOT ON A RAZOR OR PINNACLE NODE, USE TRESTLES SCRIPTS.

alias wque='~/scripts/wque_trestles.sh'

alias qi_tres01="qsub -I -l walltime=00:30:00 -q q30m32c -l nodes=1:ppn=1"

alias qi_tres32="qsub -I -l walltime=00:30:00 -q q30m32c -l nodes=1:ppn=32"

alias qi_block="read arg; qsub -I -l nodes=$arg:ppn=32"

alias pjob='~/scripts/pbs_job_watch_trestles.pl'

alias pque='~/scripts/pque_trestles.awk'

alias baby='~/scripts/baby_sitter_trestles.pl'

alias bqsub="~/scripts/batch_qsub.pl"

fi


alias clear='clear; ls'

alias ~='cd ~; clear'

alias cls='clear'

alias mv='mv -i'

alias ll='ls -lrth'

alias la='ls -aF'


alias p='cd ../'

alias blank="for ((i=0;i<60;i++)); do echo ; done"

alias diffy='diff -y -W 200'


alias pcol1="awk '{print \$1}'"

alias pcol2="awk '{print \$2}'"

alias pcol3="awk '{print \$3}'"

alias pcol4="awk '{print \$4}'"

alias pcol5="awk '{print \$5}'"

alias pcol6="awk '{print \$6}'"

alias pcol7="awk '{print \$7}'"

alias pcol8="awk '{print \$8}'"

alias pcol9="awk '{print \$9}'"

alias pcol10="awk '{print \$10}'"

alias pcol11="awk '{print \$11}'"

alias pcol12="awk '{print \$12}'"


alias math='read arg; echo "$arg" | bc -l'


alias logdir='echo `pwd` >> ~/CHECK_THESE.log' #IF COMMAND BREAKS, TRY DOUBLE QUOTES; MAY DEPEND ON SHELL TYPE.

#alias logdir="dir=`pwd`; echo \$dir >> ~/CHECK_THESE.log"


#alias lastnote='last=`ls -1rt | grep note_ | tail -n 1`; emacs $last'

#alias lastnotecat='last=`ls -1rt | grep note_ | tail -n 1`; cat $last'


## Execute upon new bash terminal:

cat ~/CHECK_THESE.log

"That's a lot of stuff... what's it doing?"

You really scrolled down here? Well, I'm glad you asked. Here we go:

The way the terminal looks & feels

These two commands remove the data size limits of "stacks" (the -s command; think "arrays" in RAM) and processes in RAM (the -r command), and send any (potential) error messages generated by these commands to computer purgatory so you won't be bothered by them:

ulimit -s unlimited 2>/dev/null

ulimit -l unlimited 2>/dev/null

On the downside, these commands also mean "idiot mode enabled," because they potentially remove the safeguards that would otherwise stop your poorly-chosen command from eating up all your RAM. So just be mindful.


If other people on your computer system/HPC will need to access (read or edit) your files/data, a umask command, if properly chosen, will save you from having to use chmod every time your colleague asks for access to a file:

umask 0027 #Default settings for who can view/edit new files you create.


Next, there's this line:

[ -z "$PS1" ] && return

Here's why that line exists. Unless you know what you're doing, just leave it alone.


This command defines what your "command prompt"-- whatever is displayed before your cursor-- will look like:

WHITE='\[\033[1;37m\]'

export PS1="$WHITE<\u@\h:\w>$ "; #Use "\w" for full path, "\W" for current directory only.

This is really a 2-in-1 command: it defines PS1=... and then activates that choice via export PS1. I've created the variable $WHITE as my plain-English version of bash for "white, bolded." $WHITE just gives your prompt a little more "oomf," and makes it easier to read, for me. The <...> are inconsequential, but I just like the look of them, and the help set the command prompt apart from any actual commands you enter. The $ (note the space!) is just traditional, as the $ is read something like "a command follows." Now, the \u@\h:\w will display user@computer:present_working_directory. For example, my full command prompt shows up as something like <tryan1@iMac:/wherever/you/are/>$ . I like to use \w (instead of \W), because I never have to type pwd. (The downside is that your command prompt will get longer and longer the deeper you move through your computer. Pick your poison.)


In order to set up colors for different objects (e.g. files, directories, symbolic links, etc.) and filetypes (e.g. png, jpeg, pdf, txt, etc.), you can (hopefully) use either this:

## Color mapping for some Linux OS.

#LS_COLORS='no=00:fi=00:di=01;31:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31:*.i386.rpm=01;31:*.src.rpm=01;30:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.png=01;35:' ;

#export LS_COLORS

or this:

## COLOR MAPPING FOR BASH ON MAC OS.

## https://mkyong.com/mac/add-color-to-the-bash-terminal-in-mac-os-x/

export CLICOLOR=1

export LSCOLORS=GxFxCxDxBxegedabagaced

but not both. There will be no harm in deleting whichever one doesn't work for your OS. I've left both largely for my personal convenience, because I work on both Macs and HPCs, and like to keep my .bashrc files as mirrored as possible across all computers/systems. Disclaimer, I borrowed the Mac LSCOLORS from the link shown in the code.

The world your terminal knows exists

Since $PATH defines the places your computer looks to learn the list of commands you can enter without having to type out their full path, adding a custom directory or two can make you a lot more efficient:

## Set the location of executables.

export PATH=$PATH:\

/Users/tryan1/scripts/:\


### Set any special location(s) of libraries required by special executables.

#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:\

#/lib64

The export PATH=$PATH:\ line means "update $PATH to be whatever it was already defined as, plus some places I will add," and the :\ means "I will add them on the next line." I do this to keep my .bashrc looking clean: only one path designated per line. My special directory, /Users/tryan1/scripts/, is where I store the source code for all the scripts I write. Normally, to use a script, I'd have a few options:

  1. Put the script in the directory I wish to use it in, and execute it via ./my_script.sh (bad idea).

  2. Leave the script in my scripts/ directory, and execute it via ./Users/tryan1/scripts/my_script.sh (lots of typing, and I'm too lazy).

  3. Put a symbolic link to the script in the directory I wish to use it in, and execute it via ./my_script.sh (not a bad idea).

However, with my scripts/ directory in my $PATH, my computer is already aware that the source code for some commands exists at /Users/tryan1/scripts/, so I can use my script anywhere on my computer simply by executing ./my_script.sh!


The lines about are $LD_LIBRARY_PATH commented out because you probably won't need them unless you're using some special software. I usually needed help from my HPC admins in order to set these properly. But just in case you're an HPC grad student, now you know. ;)

The secret language shared only between you & your terminal

This is the fun part. alias is the bash functionality that allows you to create your own "keyboard shortcuts." (Just like how you can set "tm" to be replaced by "tomorrow" when texting on your phone.) Your only limit here is your imagination. Setting convenient aliases is your chance to prove how truly lazy you and how powerful of commands you can execute with as few keys as possible. My mantra for aliases is: "if you have to type it several times in one day, you should consider making a script or alias for it."

First off, I have some examples of several ssh shortcuts in case you work on multiple computers:

alias razor="ssh trr007@sample.computer.edu"

alias trestles="ssh trr007@dummy.hpc.edu"

alias pinnacle="ssh trr007@another.example.edu"

alias newcluster="ssh trr007@more.ddns.examples.edu"

If you don't use ssh, feel free to delete these commands.

Similarly, these commands are for folks who work on multiple computers/HPCs as well:

if [[ $HOSTNAME = razor-l[123] ]] || [[ $HOSTNAME = compute???? ]]; then # WORKS FOR razor-l1 -l2 -l3 & HPC NODES.

alias qi_raz12="qsub -I -l walltime=00:30:00 -q tiny12core -l nodes=1:ppn=12"

alias qi_raz16="qsub -I -l walltime=00:30:00 -q tiny16core -l nodes=1:ppn=16"

alias qi_raz01="qsub -I -l walltime=00:30:00 -q tiny16core -l nodes=1:ppn=1"

alias qi_block12='read arg; qsub -I -q tiny12core -l nodes=$arg:ppn=12'

alias qi_block16='read arg; qsub -I -q tiny16core -l nodes=$arg:ppn=16'

elif [[ $HOSTNAME = pinnacle-l? || $HOSTNAME = c???? ]]; then # IF ON PINNACLE HPC. REQUIRES DOUBLE BRACKETS.

alias qi_comp04="srun -N 1 -n 4 --pty bash"

alias qi_comp16="srun -N 1 -n 16 --pty bash"

alias qi_comp32="srun -N 1 -n 32 --pty bash"

alias qi_condo32="srun -N 1 -n 32 --constraint fwang --pty bash"

alias qi_condo04="srun -N 1 -n 4 --constraint fwang --pty bash"

alias qi_condo01="srun -N 1 -n 1 --constraint fwang --pty bash"

alias pjob="~/scripts/ahpcc_slurmjob_watcher.sh"

else # IF NOT ON A RAZOR OR PINNACLE, USE TRESTLES SCRIPTS.

alias qi_tres01="qsub -I -l walltime=00:30:00 -q q30m32c -l nodes=1:ppn=1"

alias qi_tres32="qsub -I -l walltime=00:30:00 -q q30m32c -l nodes=1:ppn=32"

alias qi_block="read arg; qsub -I -l nodes=$arg:ppn=32"

fi

Those commands are defining different shortcuts depending on which computer you ssh-ed onto. If you really want to know, the qsub and srun commands are examples of my frequently-used interactive-job-generation requests for PBS and SLURM, respectively. (At my grad school, we had HPCs named "razor", "pinnacle", and "trestles".)


These commands modify or improve the behavior of the bash commands you type 1,000 times per day:

alias clear='clear; ls'

alias ~='cd ~; clear'

alias cls='clear'

alias mv='mv -i'

alias ll='ls -lrth'

alias la='ls -aF'

I particularly like the alias for clear. Just try it.


These are a few custom commands to create:

alias p='cd ../'

alias blank="for ((i=0;i<60;i++)); do echo ; done"

alias diffy='diff -y -W 200'

Full credit for the p alias goes to Prof. Charles Edwin Webster. I've never met anyone else who knew this alias, but I've introduced it to several people. Changing cd ../ into the single key p saves you more time than you'll ever know. You're welcome.

blank just artificially cleans up your screen. Sometimes this is needed to help clean up your reasoning powers too.

diffy will never be used alone, but along with two other arguments, e.g. diffy file1 file2. Learn to use diff first, but diffy will save you all the extra typing. The diffy alias also has a superpower in conjunction with another script I wrote.


A very cool set of commands for selective printing I found somewhere on the internet, which each mean "print column #N":

alias pcol1="awk '{print \$1}'"

alias pcol2="awk '{print \$2}'"

alias pcol3="awk '{print \$3}'"

alias pcol4="awk '{print \$4}'"

alias pcol5="awk '{print \$5}'"

alias pcol6="awk '{print \$6}'"

alias pcol7="awk '{print \$7}'"

alias pcol8="awk '{print \$8}'"

alias pcol9="awk '{print \$9}'"

alias pcol10="awk '{print \$10}'"

alias pcol11="awk '{print \$11}'"

alias pcol12="awk '{print \$12}'"

Maybe pcol 1-12 is overkill; just define however many you use. Here's an example of what these lines do.


I often find that I'd like to do some basic calculations right in my terminal. And remember, I'm lazy. I've found a valuable way to carry out some very simple (floating point) math (addition, subtraction, multiplication) without needing to reach for my handheld calculator, phone, or (heaven forbid) load python:

alias math='read arg; echo "$arg" | bc -l'

Just entering math will then await your simple math input. E.g. try 2*3.14 or 10 - 3 - 5.2 - 12.7.


This is my command for "log this directory to my to-do list reminder file." Depending on your shell/OS/computer, one of the two of these commands may/may not work for you:

alias logdir='echo `pwd` >> ~/CHECK_THESE.log' #IF COMMAND BREAKS, TRY DOUBLE QUOTES; MAY DEPEND ON SHELL TYPE.

#alias logdir="dir=`pwd`; echo \$dir >> ~/CHECK_THESE.log"

This command turned out to be a lifesaver for me in grad school while I was working on several projects at once. I often found myself doing science in several different directories at very different places on the computer; and it can be hard to remember the exact locations of each. Before going home each day, simply type logdir wherever you're working, and that directory location gets written to your ~/CHECK_THESE.log file (even if you don't have that file yet.) This .log file then becomes a helpful list of all the places you need to resuming working in tomorrow!


These two lines are designed to work with a very special set of scripts I wrote to help you with notetaking (scientists, read "lab notebook"):

#alias lastnote='last=`ls -1rt | grep note_ | tail -n 1`; emacs $last'

#alias lastnotecat='last=`ls -1rt | grep note_ | tail -n 1`; cat $last'

They're commented out here, because they won't behave properly unless you're using my notetaking scripts and workflow, described here.

Reminders & to-do lists

Just a few lines above, I described the logdir alias, which creates/writes to a file called CHECK_THESE.log. This line in the .bashrc simply serves to print the contents of that file to STDOUT as soon as you start up your bash window:

cat ~/CHECK_THESE.log

Use it like a personal secretary to remind you of things you need to do/see/remember. Absolute lifesaver when working in several places on your computer in the same week.

A subtle note:

In some cases, you will find a file at the same place as your .bashrc called .bash_profile (or maybe even .profile). In that case, you should still be able to use my .bashrc above, just add the following lines to your .bash_profile (or whatever) file:


if [ -r ~/.bashrc ]; then

source ~/.bashrc

fi