DEV Community

Jeremy Lanssiers
Jeremy Lanssiers

Posted on Edited on Originally published at Medium

Set up a reusable BASH environment for all your Linux & macOS machines

Tired of having to manually copy your favorite Bash aliases and functions to every new server or Linux distro? I solved the sync problem! I show you how to set up your Bash profile to pull configurations from a centralized Git repository. I implement some logic so those same configurations work flawlessly across various distros and machines. The payoff? A perfectly reusable and synchronized Bash environment that's always up-to-date with every commit.

Set up a Git Repo

Create or login to github.com, go to Repositories and create your GitHub repo. In this example, we'll create a repo called shell.

On your machine, create a /repos directory in /var directory and change directory into that path. If you want to use another filename or location for your Repos dir, change to that path.

mkdir /var/repos && cd /var/repos
Enter fullscreen mode Exit fullscreen mode

Also make sure your user has permissions on your repos directory.

sudo chown -R $USER:$USER /var/repos
Enter fullscreen mode Exit fullscreen mode

Inside your Repos directory, git clone the bash repo you made on GitHub.

git clone https://github.com/<username>/bash.git
Enter fullscreen mode Exit fullscreen mode

Set up your .bash_profile

Inside your user's .bash_profile (located in your home directory), add the following lines:

if [[ -f "${HOME}/.bashrc" ]]; then
    source "${HOME}/.bashrc"
fi
Enter fullscreen mode Exit fullscreen mode

Next, inside your user's .bashrc (also located in your home directory), add the following lines:

export REPOS_DIR="/var/repos"
export WORK_REPOS_DIR="${REPOS_DIR}/work" 
export MY_REPOS_DIR="${REPOS_DIR}/personal" 

export SHELL_UTILS_DIR="${MY_REPOS_DIR}/shell"
if [[ -f "${SHELL_UTILS_DIR}/index.sh" ]]; then
    source "${SHELL_UTILS_DIR}/index.sh"
fi
Enter fullscreen mode Exit fullscreen mode

This file will allow you to use two environment variables across any shell you start, but it will also load all your configs from index.sh, in which we will add and create all kinds of shell customizations.

Set up bash configurations & functions

In the shell repo, create file called index.sh, aliases.sh and prompt.sh. Also create a directory functions with and an additional index.sh.

Inside your root index.sh, add a shebang and references to the bash aliases, bash functions and prompt file:

if [ -f ${SHELL_UTILS_DIR}/aliases.sh ]; then
    . ${SHELL_UTILS_DIR}/aliases.sh
fi    

if [ -f ${SHELL_UTILS_DIR}/functions/index.sh ]; then
    . ${SHELL_UTILS_DIR}/functions/index.sh
fi

# Zsh exclusives

if [ -n "$ZSH_VERSION" ]; then

    # Oh my Zsh
    export ZSH="${HOME}/.oh-my-zsh"

    ZSH_THEME="robbyrussell"

    source ${ZSH}/oh-my-zsh.sh

    # Prompt string
    precmd() {
      print ""
    }
fi

# Bash exclusives

if [ -n "$BASH_VERSION" ]; then
    if [ -f ${SHELL_UTILS_DIR}/prompt.sh ]; then
        . ${SHELL_UTILS_DIR}/prompt.sh
    fi
fi

Enter fullscreen mode Exit fullscreen mode

These lines reference all the bash configs, aliases and functions we want to add to our bash environment on every machine. And the bashrc.sh itself will be loaded in the .bashrc we adapted earlier.

If you want, you can set different locations for your repos directory on each machine. The reusability of SHELL_UTILS_REPO is practical because you may want to set aliases to files or scripts inside your bash repo. They will work on each machine, if you reuse ${SHELL_UTILS_REPO} in your aliases or scripts.

Inside aliases.sh, add useful aliases you want to reuse on every machine, e.g.

alias my-ip="echo $(curl -s ifconfig.me)";
Enter fullscreen mode Exit fullscreen mode

This example is a command to print your IP address.

Inside functions.sh, add useful functions you want to reuse on every machine, e.g.

get_os() {
    uname -s
}

get_cores() {
    if [[ "$(uname -s)" == "Darwin" ]]; then
      echo $(sysctl -n hw.ncpu)
    else
      echo $(nproc || grep -c ^processor /proc/cpuinfo)
    fi
}
Enter fullscreen mode Exit fullscreen mode

This example is a function that will print your current Linux distro (the command is not available on macOS).

Inside prompt.sh, customize your command prompt, e.g.

#!/bin/bash
#
# Bash prompt string

# Get current git branch 

git_branch() {
    local branch
    branch=$(git branch --show-current 2>/dev/null)

    [ -n "$branch" ] && echo " (${branch})"
}

# Set colors

set_yellow='\[\e[33m\]'
set_green='\[\e[32m\]'
set_red='\[\e[1;31m\]'
reset='\[\e[0m\]'

ps_path="${set_yellow}\w${reset}"
ps_git_branch="${set_green}\$(git_branch)${reset}"
ps_symbol="${set_red}\$${reset}"

# \u: the username of the current user.
# \h: the hostname up to the first dot (.) in the Fully-Qualified Domain Name.
# \W: the basename of the current working directory, with $HOME abbreviated with a tilde (~).

PS0='\n'
PS1="\n${ps_path}${ps_git_branch} ${ps_symbol} "
PS2=''
Enter fullscreen mode Exit fullscreen mode

This example will adapt your command prompt.

Set an update function that can be executed on any Linux distro

We create a bash function called “update” that we can execute on any Linux distro to update our machine.

Inside your bash_functions.sh, add the following lines:

update() {
    if [[ $(get_os) == *"Ubuntu"* ]]; then
        sudo echo -e "updating available software\n----"
        sudo apt-get update;
        echo -e "\nupgrading software\n----"
        sudo apt-get upgrade;
        echo -e "\nremoving obsolete dependency software\n----"
        sudo apt-get autoremove --purge;
        echo -e "\nremoving software in local cache\n----"
        sudo apt-get clean;
        echo "Done"
    elif [[ $(get_os) == *"Fedora"* ]]; then
        sudo echo -e "updating available software\n----"
        sudo dnf upgrade
        echo -e "\nremoving obsolete dependency software\n----"
        sudo dnf autoremove
        echo -e "\nremoving software in local cache\n----"
        sudo dnf clean all
        echo "Done"
    fi
}
Enter fullscreen mode Exit fullscreen mode

In this example, we set an update function that uses the get_OS function to match it with a distro. In case of Ubuntu, we run updates and clean after with apt-get. In case of Fedora, we run updates and clean after with dnf. This can be extended with other distros.

Set a cleanup function that can be executed on each machine

Create a clean.sh file in your bash repo.

touch ${SHELL_UTILS_REPO}/clean.sh
Enter fullscreen mode Exit fullscreen mode

Inside clean.sh, add the following lines:

#!/bin/bash
#
# Tidy your machine

# General file paths

file_paths=("${HOME}/Desktop/*" "${HOME}/Downloads/*" "${HOME}/Pictures/Screen*")

# Linux-specific file paths

if [ $(uname) == "Linux" ]; then
    file_paths+=("${HOME}/.local/share/Trash/files/*")
fi

# MacOS-specific file paths

if [ $(uname) == "Darwin" ]; then
    file_paths+=("${HOME}/.Trash/*")
    file_paths+=("${HOME}/Library/Mobile\ Documents/com\~apple\~CloudDocs/.Trash/*")
fi

# Remove file paths

for file_path in ${file_paths[@]}; do
    rm -rf "${file_path}"
done

exit 0
Enter fullscreen mode Exit fullscreen mode

In this example, we create an array of general file paths that need to be cleaned. Then we append file paths to that array, depending on the type of OS. Finally, we iterate over the array and remove (recursively and forced) all the files on that file path. Notice the * after each file path, which makes sure only the children of that directory are deleted.

Top comments (0)