Shell Script: Yes / No Prompt, Heredoc, in Place Edits and More
In this video we'll go over a practical example of how I used all of these features in a project renaming shell script.
I recently created a shell script to help rename your project in my Docker + Flask starter kit. I thought it would be fun to make a video around the script itself because it covers a couple of patterns I find myself Googling all the time.
# Going Over a Project Rename Script
Timestamps
- 0:54 – The short version on why I created this script
- 2:02 – Running the script to get an idea of how it works
- 3:43 – Ensuring variables are set and are what we expect
- 4:47 – Creating multi-line strings using a heredoc
- 6:12 – Choosing to use
printf
for a multi-line string in one case - 9:13 – Running a sub-shell and doing variable interpolation inside of a heredoc
- 10:03 – Creating a yes / no prompt that only accepts
Yy
orNn
- 11:40 – Adding -r to the read command to make ShellCheck happy
- 12:39 – Another yes / no prompt for initializing a git repo
- 13:26 – Doing a cross platform recursive find / replace in files on Linux and macOS
- 17:32 – How I went from doing this manually to making a script and refactoring it a bit
- 18:33 – Getting trolled by your brain before you sleep
- 19:56 – A quick recap on how
set -e
andset -o pipefail
works
Code snippets
Here’s a few examples taken from the video:
Making sure variables are set
In this case both variables are coming in as command line arguments to the script. We want them both to be set before continuing with the script.
if [ -z "${APP_NAME}" ] || [ -z "${MODULE_NAME}" ]; then
echo "You must supply both an app and module name, example: ${0} myapp MyApp"
exit 1
fi
heredoc
This lets you create multi-line strings in a what you see is what you get way.
cat << EOF
When renaming your project you'll need to re-create a new database.
This can easily be done with Docker, but before this script does it
please agree that it's ok for this script to delete your current
project's database(s) by removing any associated Docker volumes.
EOF
Yes / No prompt
This will only accept YyNn
as answers. Entering in any other characters will
cause it to loop back around and ask the question again.
while true; do
read -p "Run docker-compose down -v (y/n)? " -r yn
case "${yn}" in
[Yy]* ) docker-compose down -v; break;;
[Nn]* ) exit;;
* ) echo "";;
esac
done
Default to the main branch with git
Here’s one way to do it without depending on having a modern version of git
installed.
git init
git symbolic-ref HEAD refs/heads/main
As soon as you add and commit files you’ll see them on the main
branch.
Recursive find / replace
The only thing I changed based on the video is using hard coded strings to make it easier to re-use this example.
find . -type f -exec perl -i -pe "s/oldname/newname/g" {} +
It’s worth pointing out that this works the same on Linux and macOS which IMO
makes this better than using sed -i
. That’s because sed -i
on macOS works
different than Linux due to macOS not using the GNU version of sed
.
Reference Links
- https://github.com/nickjj/docker-flask-example
- https://nickjanetakis.com/blog/linting-and-improving-your-bash-scripts-with-shellcheck
What are you planning to do for your next shell script? Let me know below.