A while ago I had the idea to store all the important configuration and dotfiles from my system in a Git repository. That saved me a few months ago: My harddrive died, but I could get back to work with Ubuntu and that repository quickly.Only problem: I maintained that repo by manually copying the files from the various directories to the repo directory. Thats what I wrote the shell script for.What does the script do?Checks whether the command is executed from within the root of a git repositoryDetects which OS its operating on (Windows, Linux or OS X) and saves that information in a variable OSAssigns variables for certain tool groups (like Bash, Git, etc.) and creates the target directories in the repo if they dont existCopies file by file to these destinationsNotes:Currently, I separate the files on a per-OS basis. This is probably unnecessary and even a hinderance. Id like to here your opinion hereThe script currently does not use any Bash >4 features, because besides Ubuntu I mainly work on Windows. I use Git Bash there which only has version 3 bundled.I also wrote a short article about this script: Backup configuration and dotfiles with Git and a shell scriptIf youre interested in current/updated versions, check out the script in the repo: get-dotfiles.sh#!/bin/bash################################################################################## Shell script to copy important configuration files from the current# environment to this repository.################################################################################## Exit as soon as a command failsset -e# Accessing an empty variable will yield an errorset -u# Assume the working directory is the path to the dotfiles repositoryREPO_PATH=$PWD/# Abort mission when were not in a git repositoryif [[ ! -d .git ]] || ! git rev-parse --git-dir > /dev/null 2>&1; then    echo Not a git repository.    exit 1fi# Detect OS (OS X, Linux or Windows)if [ $(uname) = Darwin ]; then    echo Detected system: OS X    OS=osx/    ST_DIR=$HOME/Library/Application Support/Sublime Text 3/Packages/User/elif [ $(expr substr $(uname -s) 1 5) = Linux ]; then    echo Detected system: Linux    OS=linux/    ST_DIR=$HOME/.config/sublime-text-3/Packages/User/elif [ $(expr substr $(uname -s) 1 10) = MINGW32_NT ]; then    echo Detected system: Windows    OS=win/    ST_DIR=$HOME/AppData/Roaming/Sublime Text 3/Packages/User/    NPM_DIR=$HOME/AppData/Roaming/npm/node_modules/npm/fi# Adjust destination paths so the files are separated by OSBASH_DEST=${REPO_PATH}${OS}bash/GIT_DEST=${REPO_PATH}${OS}git/NPM_DEST=${REPO_PATH}${OS}npm/RUBY_DEST=${REPO_PATH}${OS}ruby/ST_DEST=${REPO_PATH}${OS}sublime-text/declare -a destinations=($BASH_DEST $GIT_DEST $NPM_DEST $RUBY_DEST $ST_DEST)for dest in ${destinations[@]}; do    mkdir -p $destdone# Bashcp $HOME/.bashrc $BASH_DESTcp $HOME/.bash_aliases $BASH_DEST# Gitcp $HOME/.gitignore_global $GIT_DESTcp $HOME/.gitconfig $GIT_DEST# Node.js/npmcp ${NPM_DIR}.npmrc $NPM_DEST# Ruby/RubyGemscp $HOME/.gemrc $RUBY_DEST# Sublime Textcp ${ST_DIR}Preferences.sublime-settings $ST_DESTcp ${ST_DIR}Markdown.sublime-settings $ST_DESTcp ${ST_DIR}YAML.sublime-settings $ST_DESTcp ${ST_DIR}Package Control.sublime-settings $ST_DESTcp ${ST_DIR}For Loop (range).sublime-snippet $ST_DESTcp ${ST_DIR}Fraction (TeX).sublime-snippet $ST_DEST# OS specific copy operationsif [ $OS = osx/ ]; then    echo Nothing here.elif [ $OS = linux/ ]; then    cp ${ST_DIR}Default (Linux).sublime-keymap $ST_DESTelif [ $OS = windows/ ]; then    cp ${ST_DIR}Default (Windows).sublime-keymap $ST_DESTfiecho Completed.(Shell scripts are new terrain for me, I probably made some faulty assumptions. Still, dont have mercy.)
Shell script that copies configuration and dotfiles to repository
bash;shell
This is pretty nicely written. I have a couple of tips to improve it though.Don't include trailing / in path variablesAlthough there's absolutely nothing wrong with this:REPO_PATH=$PWD/# ...OS=osx/# ...BASH_DEST=${REPO_PATH}${OS}bash/In my experience, not including the trailing slash is typically more ergonomic, and sometimes even less error-prone:You might have a function that's expecting the trailing slash, and some callers might forget to append it correctly, and there's no reasonable way to enforce at compile time.When I see concatenated path-like variables like $REPO_PATH${OS}bash I'm always suspicious if the caller added the slash or not.It makes me constantly look over my shoulders and re-check all uses.Consider this alternative:REPO_PATH=$PWD# ...OS=osx# ...BASH_DEST=$REPO_PATH/$OS/bashHere, I know that $REPO_PATH/$OS/bash will be definitely close to what I expect,and no need to worry about forgotten slashes anywhere.I also know it's a path,which is less obvious in the case of the original.Don't execute the same thing repeatedlyWhen you detect the OS,the script might execute uname 3 times.It would be better to run it once and save in a variable.Avoid exprexpr is archaic. Usually there are better solutions.You could also simplify the OS detection conditions using [[ instead:uname=$(uname -s)   # Detect OS (OS X, Linux or Windows)if [[ $uname = Darwin ]]; then    echo Detected system: OS X    OS=osx    ST_DIR=$HOME/Library/Application Support/Sublime Text 3/Packages/User/elif [[ $uname == *Linux* ]]; then    echo Detected system: Linux        OS=linux    ST_DIR=$HOME/.config/sublime-text-3/Packages/User/elif [[ $uname == *MINGW32_NT* ]]; then    echo Detected system: Windows       OS=win    ST_DIR=$HOME/AppData/Roaming/Sublime Text 3/Packages/User/    NPM_DIR=$HOME/AppData/Roaming/npm/node_modules/npm/fiQuote paths that may contain spacesIt's not obvious that these paths will never contain spaces:declare -a destinations=($BASH_DEST $GIT_DEST $NPM_DEST $RUBY_DEST $ST_DEST)It's better to be safe, and put double-quotes around each.More careful error handlingIf you couldn't detect the OS, I suggest to print a warning and exit.Use case for switchesThe final OS-specific operations could be written a bit cleaner using a case statement.