These are the first lines of code I've ever written. I've been interested in the idea of learning to program for quite a while, but never really pulled the trigger, and now I've been playing around with some HTML & CSS and thought this might be a good starter project. So after a couple of days of furious googling, I managed to cobble this script together.
What I'm mostly curious about is the overall logic and structure of the code. The whole script grew organically from me looking up the Bash constructs and figuring out how to combine them to do what I want, so I don't know how sensible it is from the programming standpoint.
The idea is to keep the script in my project's folder and use relative paths, so I can just run it when I need to regenerate the CSS.
#!/bin/bash
# CSS ruleset template:
#
# .________::before { background-image: url(data:________;base64,__________); }
# filename mimetype base64 str
#
# CSS class names and other identifiers can contain the characters
# A-Z, a-z, 0-9, hyphen, underscore and Unicode characters U+00A0 and higher.
# They cannot start with a digit, two hyphens or a hyphen followed by a digit.
# (https://www.w3.org/TR/CSS2/syndata.html#characters)
#
# url(), unquoted, requires escaping the characters ()'" and whitespace.
# url('') & url("") require escaping newlines and the quote used for quoting.
# (https://www.w3.org/TR/CSS2/syndata.html#uri)
#
# Base64 encoding uses characters A-Z, a-z, 0-9 and any two of these: +-.,:/_~
# Therefore, there's never need to escape anything, so no quotes are necessary.
css_path="icons.css" # relative to the script
cd "${BASH_SOURCE%/*}"
: > "$css_path"
for file in icons/*; do
echo Processing "$file"
filename="$(name_ext="${file##*/}"; echo "${name_ext%.*}")"
ext="${file##*.}"
shopt -s nocasematch
case "$ext" in
avif ) mime="image/avif" ;;
bmp ) mime="image/bmp" ;;
gif ) mime="image/gif" ;;
jpg | jpeg) mime="image/jpeg" ;;
png ) mime="image/png" ;;
svg ) mime="image/svg+xml";;
* ) mime="unsupported" ;;
esac
if [[ "$mime" = "unsupported" ]]; then
unsupported+=("$file")
elif [[ ! "$filename" =~ ^-?[A-Za-z_][A-Za-z0-9_-]*$ ]]; then
invalid_class_name+=("$file")
else
base64str="$(base64 --wrap=0 "$file")"
printf ".%s::before { background-image: url(data:%s;base64,%s); }\n" \
"$filename" "$mime" "$base64str" \
>> "$css_path"
fi
done
if [[ -z "$unsupported" && -z "$invalid_class_name" ]]; then
echo "All done!"
else
if [[ -n "$unsupported" ]]; then
printf "\n\n%s\n\n" "UNSUPPORTED FILES (SKIPPED)"
printf " %s\n" "${unsupported[@]}"
fi
if [[ -n "$invalid_class_name" ]]; then
printf "\n\n%s\n" "FILENAMES INVALID AS CSS CLASS NAMES (SKIPPED)"
printf " %s\n" "Allowed characters: A-Z, a-z, 0-9, '-', '_'"
printf " %s\n\n" "Can't begin with: 0-9, '--', '-0' through '-9'"
printf " %s\n" "${invalid_class_name[@]}"
fi
fi
```