A Bash Script for Jekyll Development
I'm a fan of the static site generator Jekyll. It can do as much or as little as you want it to do, simply providing the directory structure or organizing your content all the way to the look and feel with templates. Personally, I only wanted Jekyll for its organization, integration with GitHub Pages, and built-in support for markdown and the Liquid templating language. Everything else was up to me, the HTML, CSS, JavaScript, and little additions like LaTeX support and the darkmode.js widget (really cool and not that little).
I'll be modifying the layout and content of this site for the foreseeable future, so I needed a convenient way to open my development environment and gets things running quickly. I like to use Vim as much as possible for things; it makes me feel like I know something about computers. I'll outline the steps I take to start developing.
Steps
- Open a terminal and navigate to my jekyll website directory.
git pullto make sure there aren't changes I pushed from another machine.tmux new -s jekyllto open a new terminal session within the current session.bundle exec jekyll serveto serve my website via localhost.- Ctrl+B D to detach from the virtual terminal.
- Open firefox and navigate to http://127.0.0.1:4000.
- Return to the terminal and open the files I need to edit in Vim.
After following this routine perhaps over 100 times, I decided a bash script was in order.
Script
#!/bin/bash
# 2025-05-19
# A simple script to help me setup my vim development environment for jekyll
if [[ $2 ]];then
echo "Too many arguments. Usage: jek [ start | stop ]"
return 1
fi
if [[ $1 == "" ]];then
echo "Too few arguments. Usage: jek [ start | stop ]"
return 1
fi
if [[ $1 == "start" ]];then
cd ~/path/to/jekyll/website/dir/
git pull
tmux new -d -s jekyll
tmux send-keys -t jekyll "bundle exec jekyll serve" ENTER
firefox & > /dev/null
sleep 5
firefox http://localhost:4000 & disown > /dev/null
ls
return 0
fi
if [[ $1 == "stop" ]];then
tmux kill-session -t jekyll
tmux ls
echo "Stopped."
return 0
fi
echo "Invalid argument. Usage: jek [ start \| stop ]"
return 1
Script Breakdown
Error handling for when the user inputs more than one argument.
if [[ $2 ]];then
echo "Too many arguments. Usage: jek [ start | stop ]"
return 1
fi
Error handling for when the user inputs less than one argument.
if [[ $1 == "" ]];then
echo "Too few arguments. Usage: jek [ start | stop ]"
return 1
fi
Inside the third if statement block, the condition for starting development.
-
Make sure everything is up to date
cd ~/path/to/jekyll/website/dir/ git pull -
Open new virtual terminal with terminal multiplexor without entering it. From the parent terminal, send a command to the virtual terminal to start the local jekyll server.
tmux new -d -s jekyll tmux send-keys -t jekyll "bundle exec jekyll serve" ENTER -
Launch firefox in the background, open a tab with localhost, and send any stdout messages into oblivion.
firefox & > /dev/null sleep 5 firefox http://localhost:4000 & disown > /dev/null ls return 0
The condition for stopping development.
if [[ $1 == "stop" ]];then
tmux kill-session -t jekyll
tmux ls
echo "Stopped."
return 0
fi
Error handling for invalid arguments, anything other than "start" or "stop".
echo "Invalid argument. Usage: jek [ start | stop ]"
return 1
Why Return Instead of Exit?
Ordinarily, when a bash script needs to terminate early, an exit statement is used. Scripts run in a separate process, so exiting a script means exiting that process to return to the shell that called it.
My script needs to change my directory to that of the jekyll website. If I run it as a script, the directory change won't persist when the script ends and the separate process terminates. To get around this, I created an alias that calls the script as a shell function by prepending a dot. That way, it won't create a separate process.
echo "alias jek='. ~/path/to/script'" >> ~/.bashrc
In my case, I keep a separate file ~/.bash_aliases that links to the ~/.bashrc file.
Since my script runs as a shell function, if I used exit statements, the whole shell would close. Instead, I used return statements, which only affect the running of the shell function.
That's It
Initially, the script was much simpler, but I added in the error handling and messages for posterity. I'm always happy to find an excuse to write a bash script!





