Skip to content

Instantly share code, notes, and snippets.

@stekern
Created June 23, 2022 13:29
Show Gist options
  • Save stekern/23e4804c0801520b50c0c3e5b3822138 to your computer and use it in GitHub Desktop.
Save stekern/23e4804c0801520b50c0c3e5b3822138 to your computer and use it in GitHub Desktop.
Shell script for replacing placeholders in files in a portable-ish manner
#!/usr/bin/env bash
#
# Helper functions for replacing placeholders in files.
#
# Distributed under terms of the MIT license.
set -euo pipefail
IFS=$'\n\t'
# Print example usage of the script.
usage() {
local script_name script_name="$(printf "%s\n" "$(basename "$0")")"
cat <<EOF
USAGE: $script_name ACTION [OPTIONS]
EXAMPLES:
$script_name --my-placeholder-name "my-placeholder-value"
EOF
exit 0
}
# Utility function for asking for confirmation
confirm() {
local query yn
query="$1"
while true; do
read -rp "$query " yn
case $yn in
yes ) return 0;;
[nN]* ) return 1;;
* ) printf "Please answer yes or no.\n";;
esac
done
}
# Replace placeholders in a predefined set of files
# The characters `<` and `>` are used as delimiters to define a placeholder.
#
# Append `|strip` to the name of the placeholder (e.g., `<my-placeholder|strip>`)
# to remove everything except "standard" characters (alphanumeric, hyphen, underscore or period) in the desired replacement value.
#
# Append `|lowercase` to the name of the placeholder (e.g., `<my-placeholder|lowercase>`)
# to force the desired replacement value to lowercase.
replace_placeholders() {
local placeholders values search_files timestamp \
i placeholder value f
placeholders=()
values=()
while [ -n "${1:-}" ]; do
case "$1" in
--*) placeholders+=("${1#"--"}"); shift; if test -n "${1:-}"; then values+=("$1"); shift; else echo "Missing placeholder value"; exit 1; fi;;
*) echo "Unknown parameter format '$1'"; exit 1 ;;
esac
done
search_files=()
while read -r -d ''; do
search_files+=("$REPLY")
done < <(find . \( \
-name "node_modules" -prune -false \
-o -wholename "./Jenkinsfile" \
-o -wholename "*/src/config.ts" \
\) -print0)
timestamp="$(date +%s)"
if [ "${#search_files[@]}" -gt 0 ]; then
printf "Found the following files:\n---\n"
printf "%s\n" "${search_files[@]}"
printf "\n\n"
if [ ! "${AUTO_CONFIRM:-false}" = "true" ]; then
if ! confirm "Do you want to replace placeholders in these files?"; then
exit 1
fi
fi
fi
for i in "${!placeholders[@]}"; do
placeholder="${placeholders[i]}"
value="${values[i]}"
for f in "${search_files[@]}"; do
# GNU and FreeBSD sed work in different ways. This command should work for both
sed -i."${timestamp}.tmp" \
-e "s/<$placeholder>/$value/g" \
-e "s/<${placeholder}[|]strip>/$(echo "$value" | sed 's/[^a-zA-Z0-9_.-]//g')/g" \
-e "s/<${placeholder}[|]lowercase>/$(echo "$value" | tr '[:upper:]' '[:lower:]')/g" \
"$f" && test -f "$f.$timestamp.tmp" && rm "$f.$timestamp.tmp"
done
done
}
main() {
if [ $# -eq 0 ]; then
usage
fi
case "$1" in
--help)
usage
;;
*)
replace_placeholders "$@"
;;
esac
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment