patternbashMinor
Shell script that copies configuration and dotfiles to repository
Viewed 0 times
scriptcopiesshellthatrepositoryandconfigurationdotfiles
Problem
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. That’s what I wrote the shell script for.
What does the script do?
Notes:
```
#!/bin/bash
################################################################################
#
# Shell script to copy important configuration files from the current
# environment to this repository.
#
################################################################################
# Exit as soon as a command fails
set -e
# Accessing an empty variable will yield an error
set -u
# Assume the working directory is the path to the dotfiles repository
REPO_PATH="$PWD/"
# Abort mission when we’re not in a git repository
if [[ ! -d .git ]] || ! git rev-parse --git-dir > /dev/null 2>&1; then
echo "Not a git repository."
exit 1
fi
# Detect OS (OS X, Linux o
Only problem: I maintained that repo by manually copying the files from the various directories to the repo directory. That’s 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 repository
- Detects which OS it’s operating on (Windows, Linux or OS X) and saves that information in a variable
OS
- Assigns variables for certain tool groups (like Bash, Git, etc.) and creates the target directories in the repo if they don’t exist
- Copies file by file to these destinations
Notes:
- Currently, I separate the files on a per-OS basis. This is probably unnecessary and even a hinderance. I’d like to here your opinion here
- The 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 script
- If you’re 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 fails
set -e
# Accessing an empty variable will yield an error
set -u
# Assume the working directory is the path to the dotfiles repository
REPO_PATH="$PWD/"
# Abort mission when we’re not in a git repository
if [[ ! -d .git ]] || ! git rev-parse --git-dir > /dev/null 2>&1; then
echo "Not a git repository."
exit 1
fi
# Detect OS (OS X, Linux o
Solution
This is pretty nicely written. I have a couple of tips to improve it though.
Don't include trailing
Although there's absolutely nothing wrong with this:
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
It makes me constantly look over my shoulders and re-check all uses.
Consider this alternative:
Here, I know that
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 repeatedly
When you detect the OS,
the script might execute
It would be better to run it once and save in a variable.
Avoid
You could also simplify the OS detection conditions using
Quote paths that may contain spaces
It's not obvious that these paths will never contain spaces:
It's better to be safe, and put double-quotes around each.
More careful error handling
If you couldn't detect the OS, I suggest to print a warning and exit.
Use
The final OS-specific operations could be written a bit cleaner using a
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/bash"Here, 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 repeatedly
When 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 spaces
It'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 handling
If 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.Code Snippets
REPO_PATH="$PWD/"
# ...
OS="osx/"
# ...
BASH_DEST="${REPO_PATH}${OS}bash/"REPO_PATH=$PWD
# ...
OS=osx
# ...
BASH_DEST="$REPO_PATH/$OS/bash"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/"
fideclare -a destinations=($BASH_DEST $GIT_DEST $NPM_DEST $RUBY_DEST $ST_DEST)Context
StackExchange Code Review Q#90972, answer score: 6
Revisions (0)
No revisions yet.