A Practical Shell Scripting Introduction for JavaScript Engineers
Compact rundown though shell basics focusing on practical use cases in JavaScript projects.
When developing scripts, I always had a tendency to go for Node.js instead of shell, even for relatively simple things. Shell scripting has always been challenging for me, until I dedicated some time in learning the basics. Now I understand that, when used correctly, shell scripts can really simplify the logic. So, here are some core concepts and practical use cases that you can learn and hopefully apply in your projects.
Essential Commands
Here is a list of some of the more common shell commands that you'd encounter in JS projects:
echo
- prints text terminal window (e.g.,echo Build is complete!
)- Files and folders:
mkdir
creates directories (e.g. create directories recursivelymkdir -p dist/code
)rm
- removes files or directories (e.g. forcibly and recursively removedist
directory -rm -rf dist
)cp
copy files and directories (e.g.,cp -f dist/404/index.html dist/404.html
)mv
move or rename files or directories (e.g.,mv -f gen/robots.txt gen/manifest.json dist
)
tar
- archiving utility (e.g., create a gzipped archive and write it to a file -tar -czf bundle.tar.gz dist/
)
There are many more commands (ls
, cd
, cat
, etc.), but when encountered you can look the up in the manual pages (e.g., man tar
). There's also a very nifty community-driven tool called tldr, that aims to simplify the beloved man pages with practical examples (e.g., tldr tar
).
Essential Operators
Command Chaining Operators
Usage of a single command is rarely enough, so here some chaining operators:
&&
(the AND operator) - executes second command only if the first one succeeds (e.g.,yarn && yarn build && yarn publish
);
(the semicolon operator) - runs several commands, despite if previous one succeeded or not (e.g.,yarn build && mv -f gen/sitemap.xml dist; echo Build done!
)
There are many more shell operators, but these and npm-run-all
should cover the majority of your chaining needs.
Output >
and Output Append >>
Operators
Both, output >
and output append >>
operators redirects content to a destination, but only >>
appends to the target. E.g., creating a .env
file in your CI pipeline:
1echo "PORT=${PRODUCTION_PORT}" > .env2echo "API_URL=${PRODUCTION_API_URL}" >> .env
Command Substitution
Command substitution is a mechanism by which the shell performs a given set of commands and then exchanges their output in the place of the commands. E.g., combine Node.js script evaluation and command substitution to have JavaScript output in shell environment:
1echo Version - $(node -e "console.log(require('./package.json').version)")
Conditional Statements
Just like JavaScript, shell scripts can have if
statements. They can be written as both multi and single line statements. E.g., performing an optimized yarn
install for CI environment only:
1#!/bin/bash23if [[ $CI ]]; then4 yarn --cache-folder $PWD/.yarn --prefer-offline --frozen-lockfile5else6 yarn7fi
Environment Variables
Environment variables are a common way of passing dynamically configurable values. Here are some use cases:
- Configurable environment values with defaults - e.g., optional
PORT
environment variable with defaults from npm config:
1{2 "config": {3 "port": 12344 },5 "srcipts": {6 "start": "serve -l ${PORT:-$npm_package_config_port}"7 }8}
- Reusing
.env
file in shell sessions - e.g., a localhost release script for Lerna project that loads.env
, and performs some necessary checks:
1#!/bin/bash23set -a4source .env5set +a67if [[ ! $GH_TOKEN ]]; then8 echo "🚨 Missing GH_TOKEN env variable" && exit 19fi1011if [[ ! $(npm whoami) ]]; then12 echo "🚨 Not logged in to npm" && exit 113fi1415if [[ ! $(git status --porcelain) ]]; then16 git checkout main && git pull && yarn release17else18 git status --porcelain19 echo "🧹 Working directory not clean" && exit 120fi
Conclusion
Shell scripting is a powerful and elegant way to perform some common operations. Dedicate some time and give it a proper try - it's a versatile skill to have at your tool belt. This blog post scratches only the surface of what's possible, so here are some resources for further reading:
Software Engineer
I build stuff using JavaScript and share my findings from time to time. I hope you will find something useful here.