Big commit, mostly adding best-practice changes to the script.

1. Added lines at the top to exit the script if any command in
the script fails.
2. Quoted all variable accesses.
3. Redirected error messages to stderr.
4. Used '[[' and ']]' in 'if' statements.
5. Added a debug mode, that can be triggered by setting the TRACE
environment variable to 1.
6. Used 'dirname' instead of 'PWD'. Therefore, in order to use the
script, you must place it in the same directory as your website
files. However, you can run it from anywhere as long as it is in
the correct location.
master
Aadhavan Srinivasan 8 months ago
parent cc3bdae903
commit 45a136dfc3

@ -1,24 +1,32 @@
#!/bin/bash #!/usr/bin/env bash
BASE_PATH="$PWD" set -o errexit # Stop executing when a command fails
set -o nounset # Stop executing when accessing an unset variable
set -o pipefail # Treat a pipeline as failing, even if one command in the pipeline fails
if [[ "${TRACE-0}" == "1" ]]; then set -o xtrace; fi # Enable tracing (output of each command) if the TRACE variable is set
BASE_PATH="$(dirname "$0")"
check_for_dirs() { check_for_dirs() {
if [ ! -d "${BASE_PATH}/source" ]; then if [[ ! -d "${BASE_PATH}/source" ]]; then
echo "ERROR: 'source' folder does not exist. Your content is sourced from this folder." echo "ERROR: 'source' folder does not exist. Your content is sourced from this folder." >&2
exit exit
fi fi
if [ -d "${BASE_PATH}/temp" ]; then if [[ -d "${BASE_PATH}/temp" ]]; then
echo "ERROR: You have an existing 'temp' folder. Please delete this folder, and run the script again." echo "ERROR: You have an existing 'temp' folder. Please delete this folder, and run the script again." >&2
exit exit
fi fi
if [ ! -f "${BASE_PATH}/header.html" ]; then if [[ ! -f "${BASE_PATH}/header.html" ]]; then
echo "ERROR: You do not have a header.html file. This file is used as a global header. Please create this file, and run the script again." echo "ERROR: You do not have a header.html file. This file is used as a global header. Please create this file, and run the script again." >&2
exit exit
fi fi
if [ ! -f "${BASE_PATH}/footer.html" ]; then if [[ ! -f "${BASE_PATH}/footer.html" ]]; then
echo "ERROR: You do not have a footer.html file. This file is used as a global footer. Please create this file, and run the script again." echo "ERROR: You do not have a footer.html file. This file is used as a global footer. Please create this file, and run the script again." >&2
exit exit
fi fi
@ -36,12 +44,12 @@ setup_output_dir() {
} }
del_files_in_output() { del_files_in_output() {
find $BASE_PATH/output -type f -name "*.md" -delete #Delete all .md files (which were copied over from 'source') in 'output' find "$BASE_PATH/output" -type f -name "*.md" -delete #Delete all .md files (which were copied over from 'source') in 'output'
} }
read_metadata() { read_metadata() {
# Read the metadata from the top of a .md file into a string # Read the metadata from the top of a .md file into a string
metadata=$(awk 'BEGIN{RS = "\n\n"} {print $0}; {exit}' $1) # Reads from the .md file until a double-newline is encountered metadata=$(awk 'BEGIN{RS = "\n\n"} {print $0}; {exit}' "$1") # Reads from the .md file until a double-newline is encountered
} }
convert_to_array() { convert_to_array() {
@ -57,52 +65,52 @@ convert_to_array() {
} }
add_date_to_array() { add_date_to_array() {
if [[ "${meta_array[date]}" == "auto" ]]; then # If the date is set to 'auto' if [[ "${meta_array[date]-}" == "auto" ]]; then # If the date is set to 'auto'
meta_array["date"]="$(date -r $1 +'%b %d, %Y')" meta_array["date"]="$(date -r $1 +'%b %d, %Y')"
fi fi
} }
add_header_and_footer() { add_header_and_footer() {
# Copy header to temporary location # Copy header to temporary location
cp $BASE_PATH/header.html $BASE_PATH/temp/temp_header.html cp "$BASE_PATH/header.html" "$BASE_PATH/temp/temp_header.html"
# Check for relevant metadata, and perform corresponding action # Check for relevant metadata, and perform corresponding action
if test -z "${meta_array[date]}"; then #If there is no date if [[ ! -v "meta_array["date"]" ]]; then # If there is no date
sed -i '$ d' $BASE_PATH/temp/temp_header.html # remove the 'date published' section of the header sed -i '$ d' "$BASE_PATH/temp/temp_header.html" # remove the 'date published' section of the header
fi fi
if [[ "${meta_array[noappend]}" == "true" ]]; then if [[ "${meta_array[noappend]-}" == "true" ]]; then
sed -i 's/ - Two More Cents//g' $BASE_PATH/temp/temp_header.html # 'noappend' removes the suffix from the title sed -i 's/ - Two More Cents//g' "$BASE_PATH/temp/temp_header.html" # 'noappend' removes the suffix from the title
fi fi
# Add header # Add header
cat $BASE_PATH/temp/temp_header.html | cat - $1 > $BASE_PATH/temp/temp.html cat "$BASE_PATH/temp/temp_header.html" | cat - "$1" > "$BASE_PATH/temp/temp.html"
# Add footer # Add footer
echo >> $BASE_PATH/temp/temp.html echo >> "$BASE_PATH/temp/temp.html" # Add newline
cat $BASE_PATH/footer.html >> $BASE_PATH/temp/temp.html cat "$BASE_PATH/footer.html" >> "$BASE_PATH/temp/temp.html"
# Move temp file to original location # Move temp file to original location
mv $BASE_PATH/temp/temp.html $1 mv "$BASE_PATH/temp/temp.html" "$1"
} }
add_header_and_footer_to_index() { add_header_and_footer_to_index() {
# Add header # Add header
cat $BASE_PATH/header.html | head -n -1 | cat - $1 > $BASE_PATH/temp/temp.html # For the index page, remove the last line of the header (date published) cat "$BASE_PATH/header.html" | head -n -1 | cat - "$1" > "$BASE_PATH/temp/temp.html" # For the index page, remove the last line of the header (date published)
# Add footer # Add footer
echo >> $BASE_PATH/temp/temp.html echo >> "$BASE_PATH/temp/temp.html" # Add newline
cat $BASE_PATH/footer.html >> $BASE_PATH/temp/temp.html cat "$BASE_PATH/footer.html" >> "$BASE_PATH/temp/temp.html"
# Move temp file to original location # Move temp file to original location
mv $BASE_PATH/temp/temp.html $1 mv "$BASE_PATH/temp/temp.html" "$1"
} }
replace_vars() { replace_vars() {
# Loop through the keys of the 'meta_array' array, search for all occurences of the key in the HTML doc, and replace them with the corresponding value.. # Loop through the keys of the 'meta_array' array, search for all occurences of the key in the HTML doc, and replace them with the corresponding value..
for arr_key in "${!meta_array[@]}"; do for arr_key in "${!meta_array[@]}"; do
meta_array[$arr_key]=${meta_array[$arr_key]/\//\\/} # Escape all forward slashes in the value meta_array["$arr_key"]="${meta_array["$arr_key"]/\//\\/}" # Escape all forward slashes in the value
sed -i "s/[\$][\$]$arr_key[\$][\$]/${meta_array[$arr_key]}/g" $1 sed -i "s/[\$][\$]$arr_key[\$][\$]/${meta_array[$arr_key]}/g" "$1"
done done
} }
@ -110,30 +118,30 @@ replace_vars() {
md_to_html() { md_to_html() {
# Convert .md files from 'source' and place them into the correct locations into 'output' # Convert .md files from 'source' and place them into the correct locations into 'output'
files=$(find $BASE_PATH/source -name "*.md") files=$(find "$BASE_PATH/source" -name "*.md")
for file in $files; do for file in $files; do
read_metadata $file # Sets the 'metadata' variable read_metadata "$file" # Sets the 'metadata' variable
convert_to_array "$metadata" #Sets the 'meta_array' array convert_to_array "$metadata" #Sets the 'meta_array' array
add_date_to_array "$file" #Uses 'meta_array' array add_date_to_array "$file" #Uses 'meta_array' array
# Copy file to temp dir and strip metadata # Copy file to temp dir and strip metadata
cp $file $BASE_PATH/temp/ cp "$file" "$BASE_PATH/temp/"
let num_lines=$(echo "$metadata" | wc -l)+1 let num_lines=$(echo "$metadata" | wc -l)+1
sed -i "1,${num_lines}d" $BASE_PATH/temp/`basename $file` sed -i "1,${num_lines}d" "$BASE_PATH/temp/$(basename "$file")"
# Construct path for output file # Construct path for output file
path_for_output=$(realpath --relative-to="${BASE_PATH}/source" $file) path_for_output=$(realpath --relative-to="${BASE_PATH}/source" "$file")
path_for_output="${BASE_PATH}/output/${path_for_output}" path_for_output="${BASE_PATH}/output/${path_for_output}"
path_for_output="$(dirname $path_for_output)/$(basename $path_for_output .md).html" path_for_output="$(dirname $path_for_output)/$(basename $path_for_output .md).html"
# Convert the file (using the given filters), and place the output in the correct location # Convert the file (using the given filters), and place the output in the correct location
pandoc --lua-filter pandoc_filters/* -f markdown --wrap=preserve $BASE_PATH/temp/`basename $file` > ${path_for_output} pandoc --lua-filter "$BASE_PATH"/pandoc_filters/* -f markdown --wrap=preserve "$BASE_PATH/temp/$(basename "$file")" > "${path_for_output}"
rm $BASE_PATH/temp/* rm "$BASE_PATH"/temp/*
add_header_and_footer $path_for_output # Uses 'meta_array' array add_header_and_footer "$path_for_output" # Uses 'meta_array' array
replace_vars $path_for_output #Uses 'meta_array' array replace_vars "$path_for_output" #Uses 'meta_array' array
unset metadata meta_key meta_value meta_array unset metadata meta_key meta_value meta_array
done done
@ -141,11 +149,12 @@ md_to_html() {
gen_sorted_file_list() { # Generate a list of the HTMl files, sorted by when they were last modified (read from the contents of the HTML file) gen_sorted_file_list() { # Generate a list of the HTMl files, sorted by when they were last modified (read from the contents of the HTML file)
files=$(find $BASE_PATH/output -name "*.html") files=$(find "$BASE_PATH/output" -name "*.html")
local date_mod
for file in $files; do for file in $files; do
if grep -q "date-published" $file; then if grep -q "date-published" "$file" ; then
echo "$file" >> $BASE_PATH/temp/file_listing.txt # Write files that have a date published to a temp file (we only want the files with date modified, because only these files can be listed with their date on the site map) echo "$file" >> "$BASE_PATH/temp/file_listing.txt" # Write files that have a date published to a temp file (we only want the files with date modified, because only these files can be listed with their date on the site map)
date_mod+=$(cat "$file" | grep "date-published" | awk -F'[<>]' '{print $3}' \ date_mod+=$(cat "$file" | grep "date-published" | awk -F'[<>]' '{print $3}' \
| cut -d' ' -f '1,2' --complement | tr -d "," | awk '{print $2" "$1" "$3}' \ | cut -d' ' -f '1,2' --complement | tr -d "," | awk '{print $2" "$1" "$3}' \
@ -155,16 +164,16 @@ gen_sorted_file_list() { # Generate a list of the HTMl files, sorted by when the
# Line 2 re-arranges this information, and converts it into DD MM YY format # Line 2 re-arranges this information, and converts it into DD MM YY format
# Line 3 converts this into a UNIX timestamp # Line 3 converts this into a UNIX timestamp
date_mod+=$'\n' date_mod+=$'\n'
fi fi
done done
date_mod=$(echo "$date_mod" | head -n -1) # Remove last (empty) line from variable date_mod=$(echo "${date_mod-}" | head -n -1) # Remove last (empty) line from variable
echo "$date_mod" > $BASE_PATH/temp/date_mod.txt # Write the corresponding 'date modified' timestamps to a temp file echo "${date_mod-}" > "$BASE_PATH/temp/date_mod.txt" # Write the corresponding 'date modified' timestamps to a temp file
paste $BASE_PATH/temp/file_listing.txt $BASE_PATH/temp/date_mod.txt > $BASE_PATH/temp/new_file_list.txt # Combine file list and date modified into a single file paste "$BASE_PATH/temp/file_listing.txt" "$BASE_PATH/temp/date_mod.txt" > "$BASE_PATH/temp/new_file_list.txt" # Combine file list and date modified into a single file
sorted_file_list=$(sort -r -k 2 $BASE_PATH/temp/new_file_list.txt) # Sort the data in the file based on the timestamp (from newest to oldest), and store it into a variable sorted_file_list=$(sort -r -k 2 "$BASE_PATH/temp/new_file_list.txt") # Sort the data in the file based on the timestamp (from newest to oldest), and store it into a variable
sorted_file_list=$(echo "$sorted_file_list" | awk '{print $1}') # Store only the first column (the file path) in the variable sorted_file_list=$(echo "$sorted_file_list" | awk '{print $1}') # Store only the first column (the file path) in the variable
} }
@ -173,16 +182,16 @@ gen_index_page() { # Generate an index page (site map) that includes links to th
index_file_html="<nav class=\"toc\">"$'\n' # Variable to store the body HTML of the index page; enclose the list in a nav index_file_html="<nav class=\"toc\">"$'\n' # Variable to store the body HTML of the index page; enclose the list in a nav
for file in $1; do for file in $1; do
title=$(cat $file | grep "<title>" | head -n 1 | awk -F'[<>]' '{print $3}') # Find the title of the web page title=$(cat "$file" | grep "<title>" | head -n 1 | awk -F'[<>]' '{print $3}') # Find the title of the web page
suffix=" - Two More Cents" suffix=" - Two More Cents"
title=${title%"$suffix"} # Remove the website name from it title="${title%"$suffix"}" # Remove the website name from it
pub_date=$(cat $file | grep "date-published" | head -n 1 | awk -F'[<>]' '{print $3}') # Find the date published pub_date=$(cat "$file" | grep "date-published" | head -n 1 | awk -F'[<>]' '{print $3}') # Find the date published
prefix="Published on " # Find date published of webpage prefix="Published on " # Find date published of webpage
pub_date=${pub_date#"$prefix"} # Remove the prefix from it pub_date="${pub_date#"$prefix"}" # Remove the prefix from it
pub_date=$(echo "$pub_date" | tr -d "," | awk '{print $2" "$1" "$3}' | date -f - +"%m/%d/%Y") # Re-arrange the date and convert to mm/dd/yy pub_date=$(echo "$pub_date" | tr -d "," | awk '{print $2" "$1" "$3}' | date -f - +"%m/%d/%Y") # Re-arrange the date and convert to mm/dd/yy
file_path=$(realpath --relative-to="${BASE_PATH}/output" $file) file_path=$(realpath --relative-to="${BASE_PATH}/output" "$file")
index_file_html+="<li><time>${pub_date}</time> - <a href=\"$file_path\">$title</a></li>" # Add a line of HTML containing the date and title of the article index_file_html+="<li><time>${pub_date}</time> - <a href=\"$file_path\">$title</a></li>" # Add a line of HTML containing the date and title of the article
index_file_html+=$'\n' index_file_html+=$'\n'
@ -200,14 +209,14 @@ gen_index_page() { # Generate an index page (site map) that includes links to th
} }
copy_things_in() { copy_things_in() {
cp ${BASE_PATH}/styles.css ${BASE_PATH}/output/ cp "${BASE_PATH}/styles.css" "${BASE_PATH}/output/"
cp -r ${BASE_PATH}/files ${BASE_PATH}/output/ cp -r "${BASE_PATH}/files" "${BASE_PATH}/output/"
cp -r ${BASE_PATH}/fonts ${BASE_PATH}/output/ cp -r "${BASE_PATH}/fonts" "${BASE_PATH}/output/"
} }
clean_up() { clean_up() {
rm -r ${BASE_PATH}/temp rm -r "${BASE_PATH}/temp"
} }

Loading…
Cancel
Save