From a0fc38d6a2b5592aa04733ff4379c3b1302816f6 Mon Sep 17 00:00:00 2001
From: Dan Schaper <dan.schaper@pi-hole.net>
Date: Wed, 31 Oct 2018 11:14:05 -0700
Subject: [PATCH] All terminal echo commands changed to printf.

Signed-off-by: Dan Schaper <dan.schaper@pi-hole.net>
---
 automated install/basic-install.sh | 526 ++++++++++++++---------------
 1 file changed, 261 insertions(+), 265 deletions(-)

diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh
index b8eb7864..2a08ce17 100755
--- a/automated install/basic-install.sh	
+++ b/automated install/basic-install.sh	
@@ -66,9 +66,11 @@ fi
 
 
 # Find the rows and columns will default to 80x24 if it can not be detected
-screen_size=$(stty size 2>/dev/null || echo 24 80)
-rows=$(echo "${screen_size}" | awk '{print $1}')
-columns=$(echo "${screen_size}" | awk '{print $2}')
+screen_size=$(stty size || printf '%d %d' 24 80)
+# Set rows variable to contain first number
+printf -v rows '%d' "${screen_size%% *}"
+# Set columns variable to contain second number
+printf -v columns '%d' "${screen_size##* }"
 
 # Divide by two so the dialogs take up half of the screen, which looks nice.
 r=$(( rows / 2 ))
@@ -165,11 +167,11 @@ if command -v apt-get &> /dev/null; then
     # Check for and determine version number (major and minor) of current php install
     if command -v php &> /dev/null; then
         phpInsVersion="$(php -v | head -n1 | grep -Po '(?<=PHP )[^ ]+')"
-        echo -e "  ${INFO} Existing PHP installation detected : PHP version $phpInsVersion"
-        phpInsMajor="$(echo "$phpInsVersion" | cut -d\. -f1)"
-        phpInsMinor="$(echo "$phpInsVersion" | cut -d\. -f2)"
+        printf "  %b Existing PHP installation detected : PHP version %s\\n" "${INFO}" "${phpInsVersion}"
+        printf -v phpInsMajor "%d" "${phpInsVersion%%.*}"
+        printf -v phpInsMinor "%d" "${phpInsVersion##*.}"
         # Is installed php version 7.0 or greater
-        if [ "$(echo "$phpInsMajor.$phpInsMinor < 7.0" | bc )" == 0 ]; then
+        if [ "${phpInsMajor}" -ge 7 ]; then
             phpInsNewer=true
         fi
     fi
@@ -257,8 +259,8 @@ elif command -v rpm &> /dev/null; then
         CURRENT_CENTOS_VERSION=$(grep -oP '(?<= )[0-9]+(?=\.)' /etc/redhat-release)
         # Check if CentOS version is supported
         if [[ $CURRENT_CENTOS_VERSION -lt $SUPPORTED_CENTOS_VERSION ]]; then
-            echo -e "  ${CROSS} CentOS $CURRENT_CENTOS_VERSION is not supported."
-            echo -e "      Please update to CentOS release $SUPPORTED_CENTOS_VERSION or later"
+            printf "  %b CentOS %s is not supported.\\n" "${CROSS}" "${CURRENT_CENTOS_VERSION}"
+            printf "      Please update to CentOS release %s or later.\\n" "${SUPPORTED_CENTOS_VERSION}"
             # exit the installer
             exit
         fi
@@ -266,9 +268,9 @@ elif command -v rpm &> /dev/null; then
         EPEL_PKG="epel-release"
         rpm -q ${EPEL_PKG} &> /dev/null || rc=$?
         if [[ $rc -ne 0 ]]; then
-            echo -e "  ${INFO} Enabling EPEL package repository (https://fedoraproject.org/wiki/EPEL)"
+            printf "  %b Enabling EPEL package repository (https://fedoraproject.org/wiki/EPEL)\\n" "${INFO}"
             "${PKG_INSTALL[@]}" ${EPEL_PKG} &> /dev/null
-            echo -e "  ${TICK} Installed ${EPEL_PKG}"
+            printf "  %b Installed %s\\n" "${TICK}" "${EPEL_PKG}"
         fi
 
         # The default php on CentOS 7.x is 5.4 which is EOL
@@ -285,20 +287,20 @@ elif command -v rpm &> /dev/null; then
             # The PHP version available via default repositories is older than version 7
             if ! whiptail --defaultno --title "PHP 7 Update (recommended)" --yesno "PHP 7.x is recommended for both security and language features.\\nWould you like to install PHP7 via Remi's RPM repository?\\n\\nSee: https://rpms.remirepo.net for more information" ${r} ${c}; then
                 # User decided to NOT update PHP from REMI, attempt to install the default available PHP version
-                echo -e "  ${INFO} User opt-out of PHP 7 upgrade on CentOS. Deprecated PHP may be in use."
+                printf "  %b User opt-out of PHP 7 upgrade on CentOS. Deprecated PHP may be in use.\\n" "${INFO}"
                 : # continue with unsupported php version
             else
-                echo -e "  ${INFO} Enabling Remi's RPM repository (https://rpms.remirepo.net)"
+                printf "  %b Enabling Remi's RPM repository (https://rpms.remirepo.net)\\n" "${INFO}"
                 "${PKG_INSTALL[@]}" "https://rpms.remirepo.net/enterprise/${REMI_PKG}-$(rpm -E '%{rhel}').rpm" &> /dev/null
                 # enable the PHP 7 repository via yum-config-manager (provided by yum-utils)
                 "${PKG_INSTALL[@]}" "yum-utils" &> /dev/null
                 yum-config-manager --enable ${REMI_REPO} &> /dev/null
-                echo -e "  ${TICK} Remi's RPM repository has been enabled for PHP7"
+                printf "  %b Remi's RPM repository has been enabled for PHP7\\n" "${TICK}"
                 # trigger an install/update of PHP to ensure previous version of PHP is updated from REMI
                 if "${PKG_INSTALL[@]}" "php-cli" &> /dev/null; then
-                    echo -e "  ${TICK} PHP7 installed/updated via Remi's RPM repository"
+                    printf "  %b PHP7 installed/updated via Remi's RPM repository\\n" "${TICK}"
                 else
-                    echo -e "  ${CROSS} There was a problem updating to PHP7 via Remi's RPM repository"
+                    printf "  %b There was a problem updating to PHP7 via Remi's RPM repository\\n" "${CROSS}"
                     exit 1
                 fi
             fi
@@ -307,17 +309,17 @@ elif command -v rpm &> /dev/null; then
     else
         # Warn user of unsupported version of Fedora or CentOS
         if ! whiptail --defaultno --title "Unsupported RPM based distribution" --yesno "Would you like to continue installation on an unsupported RPM based distribution?\\n\\nPlease ensure the following packages have been installed manually:\\n\\n- lighttpd\\n- lighttpd-fastcgi\\n- PHP version 7+" ${r} ${c}; then
-            echo -e "  ${CROSS} Aborting installation due to unsupported RPM based distribution"
+            printf "  %b Aborting installation due to unsupported RPM based distribution\\n" "${CROSS}"
             exit # exit the installer
         else
-            echo -e "  ${INFO} Continuing installation with unsupported RPM based distribution"
+            printf "  %b Continuing installation with unsupported RPM based distribution\\n" "${INFO}"
         fi
     fi
 
 # If neither apt-get or yum/dnf package managers were found
 else
     # it's not an OS we can support,
-    echo -e "  ${CROSS} OS distribution not supported"
+    printf "  %b OS distribution not supported\\n" "${CROSS}"
     # so exit the installer
     exit
 fi
@@ -360,7 +362,7 @@ make_repo() {
     # The message to display when this function is running
     str="Clone ${remoteRepo} into ${directory}"
     # Display the message and use the color table to preface the message with an "info" indicator
-    echo -ne "  ${INFO} ${str}..."
+    printf "  %b %s..." "${INFO}" "${str}"
     # If the directory exists,
     if [[ -d "${directory}" ]]; then
         # delete everything in it so git can clone into it
@@ -369,7 +371,7 @@ make_repo() {
     # Clone the repo and return the return code from this command
     git clone -q --depth 1 "${remoteRepo}" "${directory}" &> /dev/null || return $?
     # Show a colored message showing it's status
-    echo -e "${OVER}  ${TICK} ${str}"
+    printf "%b  %b %s\\n" "${OVER}" "${TICK}" "${str}"
     # Always return 0? Not sure this is correct
     return 0
 }
@@ -393,14 +395,14 @@ update_repo() {
     # Move into the directory that was passed as an argument
     cd "${directory}" &> /dev/null || return 1
     # Let the user know what's happening
-    echo -ne "  ${INFO} ${str}..."
+    printf "  %b %s..." "${INFO}" "${str}"
     # Stash any local commits as they conflict with our working code
     git stash --all --quiet &> /dev/null || true # Okay for stash failure
     git clean --quiet --force -d || true # Okay for already clean directory
     # Pull the latest commits
     git pull --quiet &> /dev/null || return $?
     # Show a completion message
-    echo -e "${OVER}  ${TICK} ${str}"
+    printf "%b  %b %s\\n" "${OVER}" "${TICK}" "${str}"
     # Move back into the original directory
     cd "${curdir}" &> /dev/null || return 1
     return 0
@@ -416,19 +418,19 @@ getGitFiles() {
     # A local variable containing the message to be displayed
     local str="Check for existing repository in ${1}"
     # Show the message
-    echo -ne "  ${INFO} ${str}..."
+    printf "  %b %s..." "${INFO}" "${str}"
     # Check if the directory is a repository
     if is_repo "${directory}"; then
         # Show that we're checking it
-        echo -e "${OVER}  ${TICK} ${str}"
+        printf "%b  %b %s\\n" "${OVER}" "${TICK}" "${str}"
         # Update the repo, returning an error message on failure
-        update_repo "${directory}" || { echo -e "\\n  ${COL_LIGHT_RED}Error: Could not update local repository. Contact support.${COL_NC}"; exit 1; }
+        update_repo "${directory}" || { printf "\\n  %b: Could not update local repository. Contact support.%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
     # If it's not a .git repo,
     else
         # Show an error
-        echo -e "${OVER}  ${CROSS} ${str}"
+        printf "%b  %b %s\\n" "${OVER}" "${CROSS}" "${str}"
         # Attempt to make the repository, showing an error on failure
-        make_repo "${directory}" "${remoteRepo}" || { echo -e "\\n  ${COL_LIGHT_RED}Error: Could not update local repository. Contact support.${COL_NC}"; exit 1; }
+        make_repo "${directory}" "${remoteRepo}" || { printf "\\n  %bError: Could not update local repository. Contact support.%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
     fi
     # echo a blank line
     echo ""
@@ -445,11 +447,11 @@ resetRepo() {
     # Store the message in a variable
     str="Resetting repository within ${1}..."
     # Show the message
-    echo -ne "  ${INFO} ${str}"
+    printf "  %b %s..." "${INFO}" "${str}"
     # Use git to remove the local changes
     git reset --hard &> /dev/null || return $?
     # And show the status
-    echo -e "${OVER}  ${TICK} ${str}"
+    printf "%b  %b %s\\n" "${OVER}" "${TICK}" "${str}"
     # Returning success anyway?
     return 0
 }
@@ -505,36 +507,36 @@ verifyFreeDiskSpace() {
     # If the existing space is not an integer,
     if ! [[ "${existing_free_kilobytes}" =~ ^([0-9])+$ ]]; then
         # show an error that we can't determine the free space
-        echo -e "  ${CROSS} ${str}"
-        echo -e "  ${INFO} Unknown free disk space!"
-        echo -e "  ${INFO} We were unable to determine available free disk space on this system."
-        echo -e "  ${INFO} You may override this check, however, it is not recommended"
-        echo -e "  ${INFO} The option '${COL_LIGHT_RED}--i_do_not_follow_recommendations${COL_NC}' can override this"
-        echo -e "  ${INFO} e.g: curl -L https://install.pi-hole.net | bash /dev/stdin ${COL_LIGHT_RED}<option>${COL_NC}"
+        printf "  %b %s\\n" "${CROSS}" "${str}"
+        printf "  %b Unknown free disk space! \\n" "${INFO}"
+        printf "      We were unable to determine available free disk space on this system.\\n"
+        printf "      You may override this check, however, it is not recommended.\\n"
+        printf "      The option '%b--i_do_not_follow_recommendations%b' can override this.\\n" "${COL_LIGHT_RED}" "${COL_NC}"
+        printf "      e.g: curl -L https://install.pi-hole.net | bash /dev/stdin %b<option>%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
         # exit with an error code
         exit 1
     # If there is insufficient free disk space,
     elif [[ "${existing_free_kilobytes}" -lt "${required_free_kilobytes}" ]]; then
         # show an error message
-        echo -e "  ${CROSS} ${str}"
-        echo -e "  ${INFO} Your system disk appears to only have ${existing_free_kilobytes} KB free"
-        echo -e "  ${INFO} It is recommended to have a minimum of ${required_free_kilobytes} KB to run the Pi-hole"
+        printf "  %b %s\\n" "${CROSS}" "${str}"
+        printf "  %b Your system disk appears to only have %s KB free\\n" "${INFO}" "${existing_free_kilobytes}"
+        printf "      It is recommended to have a minimum of %s KB to run the Pi-hole\\n" "${required_free_kilobytes}"
         # if the vcgencmd command exists,
         if command -v vcgencmd &> /dev/null; then
             # it's probably a Raspbian install, so show a message about expanding the filesystem
-            echo -e "  ${INFO} If this is a new install you may need to expand your disk"
-            echo -e "  ${INFO} Run 'sudo raspi-config', and choose the 'expand file system' option"
-            echo -e "  ${INFO} After rebooting, run this installation again"
-            echo -e "  ${INFO} e.g: curl -L https://install.pi-hole.net | bash"
+            printf "      If this is a new install you may need to expand your disk\\n"
+            printf "      Run 'sudo raspi-config', and choose the 'expand file system' option\\n"
+            printf "      After rebooting, run this installation again\\n"
+            printf "      e.g: curl -L https://install.pi-hole.net | bash\\n"
         fi
         # Show there is not enough free space
-        echo -e "\\n      ${COL_LIGHT_RED}Insufficient free space, exiting...${COL_NC}"
+        printf "\\n      %bInsufficient free space, exiting...%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
         # and exit with an error
         exit 1
     # Otherwise,
     else
         # Show that we're running a disk space check
-        echo -e "  ${TICK} ${str}"
+        printf "  %b %s\\n" "${TICK}" "${str}"
     fi
 }
 
@@ -552,7 +554,7 @@ chooseInterface() {
     local firstLoop=1
 
     # Find out how many interfaces are available to choose from
-    interfaceCount=$(echo "${availableInterfaces}" | wc -l)
+    interfaceCount=$(wc -l <<< "${availableInterfaces}")
 
     # If there is one interface,
     if [[ "${interfaceCount}" -eq 1 ]]; then
@@ -579,13 +581,13 @@ chooseInterface() {
         # Now run the command using the interfaces saved into the array
         chooseInterfaceOptions=$("${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty) || \
         # If the user chooses Cancel, exit
-        { echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
+        { printf "  %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
         # For each interface
         for desiredInterface in ${chooseInterfaceOptions}; do
             # Set the one the user selected as the interface to use
             PIHOLE_INTERFACE=${desiredInterface}
             # and show this information to the user
-            echo -e "  ${INFO} Using interface: $PIHOLE_INTERFACE"
+            printf "  %b Using interface: %s\\n" "${INFO}" "${PIHOLE_INTERFACE}"
         done
     fi
 }
@@ -595,21 +597,24 @@ chooseInterface() {
 # See https://github.com/pi-hole/pi-hole/issues/1473#issuecomment-301745953
 testIPv6() {
     # first will contain fda2 (ULA)
-    first="$(cut -f1 -d":" <<< "$1")"
+    printf -v first "%d" "${1%%:*}"
     # value1 will contain 253 which is the decimal value corresponding to 0xfd
     value1=$(( (0x$first)/256 ))
     # will contain 162 which is the decimal value corresponding to 0xa2
     value2=$(( (0x$first)%256 ))
     # the ULA test is testing for fc00::/7 according to RFC 4193
     if (( (value1&254)==252 )); then
+        # echoing result to calling function as return value
         echo "ULA"
     fi
     # the GUA test is testing for 2000::/3 according to RFC 4291
     if (( (value1&112)==32 )); then
+        # echoing result to calling function as return value
         echo "GUA"
     fi
     # the LL test is testing for fe80::/10 according to RFC 4193
     if (( (value1)==254 )) && (( (value2&192)==128 )); then
+        # echoing result to calling function as return value
         echo "Link-local"
     fi
 }
@@ -635,17 +640,17 @@ useIPv6dialog() {
         # set the IPv6 address to the ULA address
         IPV6_ADDRESS="${ULA_ADDRESS}"
         # Show this info to the user
-        echo -e "  ${INFO} Found IPv6 ULA address, using it for blocking IPv6 ads"
+        printf "  %b Found IPv6 ULA address, using it for blocking IPv6 ads\\n" "${INFO}"
     # Otherwise, if the GUA_ADDRESS has a value,
     elif [[ ! -z "${GUA_ADDRESS}" ]]; then
         # Let the user know
-        echo -e "  ${INFO} Found IPv6 GUA address, using it for blocking IPv6 ads"
+        printf "  %b Found IPv6 GUA address, using it for blocking IPv6 ads\\n" "${INFO}"
         # And assign it to the global variable
         IPV6_ADDRESS="${GUA_ADDRESS}"
     # If none of those work,
     else
         # explain that IPv6 blocking will not be used
-        echo -e "  ${INFO} Unable to find IPv6 ULA/GUA address, IPv6 adblocking will not be enabled"
+        printf "  %b Unable to find IPv6 ULA/GUA address, IPv6 adblocking will not be enabled\\n" "${INFO}"
         # So set the variable to be empty
         IPV6_ADDRESS=""
     fi
@@ -670,7 +675,7 @@ use4andor6() {
     # or IPv6 (on by default if available)
     IPv6 "Block ads over IPv6" on)
     # In a variable, show the choices available; exit if Cancel is selected
-    choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty) || { echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
+    choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty) || { printf "  %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
     # For each choice available,
     for choice in ${choices}
     do
@@ -693,12 +698,12 @@ use4andor6() {
         useIPv6dialog
     fi
     # Echo the information to the user
-    echo -e "  ${INFO} IPv4 address: ${IPV4_ADDRESS}"
-    echo -e "  ${INFO} IPv6 address: ${IPV6_ADDRESS}"
+    printf "  %b IPv4 address: %s\\n" "${INFO}" "${IPV4_ADDRESS}"
+    printf "  %b IPv6 address: %s\\n" "${INFO}" "${IPV6_ADDRESS}"
     # If neither protocol is selected,
     if [[ ! "${useIPv4}" ]] && [[ ! "${useIPv6}" ]]; then
         # Show an error in red
-        echo -e "  ${COL_LIGHT_RED}Error: Neither IPv4 or IPv6 selected${COL_NC}"
+        printf "  %bError: Neither IPv4 or IPv6 selected%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
         # and exit with an error
         exit 1
     fi
@@ -728,13 +733,13 @@ It is also possible to use a DHCP reservation, but if you are going to do that,
         IPV4_ADDRESS=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 address" --inputbox "Enter your desired IPv4 address" ${r} ${c} "${IPV4_ADDRESS}" 3>&1 1>&2 2>&3) || \
         # Cancelling IPv4 settings window
         { ipSettingsCorrect=False; echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
-        echo -e "  ${INFO} Your static IPv4 address: ${IPV4_ADDRESS}"
+        printf "  %b Your static IPv4 address: %s\\n" "${INFO}" "${IPV4_ADDRESS}"
 
         # Ask for the gateway
         IPv4gw=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 gateway (router)" --inputbox "Enter your desired IPv4 default gateway" ${r} ${c} "${IPv4gw}" 3>&1 1>&2 2>&3) || \
         # Cancelling gateway settings window
         { ipSettingsCorrect=False; echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
-        echo -e "  ${INFO} Your static IPv4 gateway: ${IPv4gw}"
+        printf "  %b Your static IPv4 gateway: %s\\n" "${INFO}" "${IPv4gw}"
 
         # Give the user a chance to review their settings before moving on
         if whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Are these settings correct?
@@ -769,7 +774,7 @@ setStaticIPv4() {
     if [[ -f "/etc/dhcpcd.conf" ]]; then
         # check if the IP is already in the file
         if grep -q "${IPV4_ADDRESS}" /etc/dhcpcd.conf; then
-            echo -e "  ${INFO} Static IP already configured"
+            printf "  %b Static IP already configured\\n" "${INFO}"
         # If it's not,
         else
             # set it using our function
@@ -777,21 +782,20 @@ setStaticIPv4() {
             # Then use the ip command to immediately set the new address
             ip addr replace dev "${PIHOLE_INTERFACE}" "${IPV4_ADDRESS}"
             # Also give a warning that the user may need to reboot their system
-            echo -e "  ${TICK} Set IP address to ${IPV4_ADDRESS%/*}
-            You may need to restart after the install is complete"
+            printf "  %b Set IP address to %s \\n  You may need to restart after the install is complete\\n" "${TICK}" "${IPV4_ADDRESS%/*}"
         fi
     # If it's not Debian, check if it's the Fedora family by checking for the file below
     elif [[ -f "/etc/sysconfig/network-scripts/ifcfg-${PIHOLE_INTERFACE}" ]];then
         # If it exists,
         IFCFG_FILE=/etc/sysconfig/network-scripts/ifcfg-${PIHOLE_INTERFACE}
-        IPADDR=$(echo "${IPV4_ADDRESS}" | cut -f1 -d/)
+        printf -v IPADDR "${IPV4_ADDRESS%%/*}"
         # check if the desired IP is already set
         if grep -Eq "${IPADDR}(\\b|\\/)" "${IFCFG_FILE}"; then
-            echo -e "  ${INFO} Static IP already configured"
+            printf "  %b Static IP already configured\\n" "${INFO}"
         # Otherwise,
         else
             # Put the IP in variables without the CIDR notation
-            CIDR=$(echo "${IPV4_ADDRESS}" | cut -f2 -d/)
+            printf -v CIDR "${IPV4_ADDRESS##*/}"
             # Backup existing interface configuration:
             cp "${IFCFG_FILE}" "${IFCFG_FILE}".pihole.orig
             # Build Interface configuration file using the GLOBAL variables we have
@@ -815,13 +819,12 @@ setStaticIPv4() {
                 nmcli con load "${IFCFG_FILE}" > /dev/null
             fi
             # Show a warning that the user may need to restart
-            echo -e "  ${TICK} Set IP address to ${IPV4_ADDRESS%/*}
-            You may need to restart after the install is complete"
+            printf "  %b Set IP address to %s\\n  You may need to restart after the install is complete\\n" "${TICK}" "${IPV4_ADDRESS%%/*}"
         fi
     # If all that fails,
     else
         # show an error and exit
-        echo -e "  ${INFO} Warning: Unable to locate configuration file to set static IPv4 address"
+        printf "  %b Warning: Unable to locate configuration file to set static IPv4 address\\n" "${INFO}"
         exit 1
     fi
 }
@@ -871,49 +874,49 @@ setDNS() {
     DNSchoices=$(whiptail --separate-output --menu "Select Upstream DNS Provider. To use your own, select Custom." ${r} ${c} 7 \
     "${DNSChooseOptions[@]}" 2>&1 >/dev/tty) || \
     # exit if Cancel is selected
-    { echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
+    { printf "  %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
 
     # Display the selection
-    echo -ne "  ${INFO} Using "
+    printf "  %b Using " "${INFO}"
     # Depending on the user's choice, set the GLOBAl variables to the IP of the respective provider
     case ${DNSchoices} in
         Google)
-            echo "Google DNS servers"
+            printf "Google DNS servers\\n"
             PIHOLE_DNS_1="8.8.8.8"
             PIHOLE_DNS_2="8.8.4.4"
             ;;
         OpenDNS)
-            echo "OpenDNS servers"
+            printf "OpenDNS servers\\n"
             PIHOLE_DNS_1="208.67.222.222"
             PIHOLE_DNS_2="208.67.220.220"
             ;;
         Level3)
-            echo "Level3 servers"
+            printf "Level3 servers\\n"
             PIHOLE_DNS_1="4.2.2.1"
             PIHOLE_DNS_2="4.2.2.2"
             ;;
         Comodo)
-            echo "Comodo Secure servers"
+            printf "Comodo Secure servers\\n"
             PIHOLE_DNS_1="8.26.56.26"
             PIHOLE_DNS_2="8.20.247.20"
             ;;
         DNSWatch)
-            echo "DNS.WATCH servers"
+            printf "DNS.WATCH servers\\n"
             PIHOLE_DNS_1="84.200.69.80"
             PIHOLE_DNS_2="84.200.70.40"
             ;;
         Quad9)
-            echo "Quad9 servers"
+            printf "Quad9 servers\\n"
             PIHOLE_DNS_1="9.9.9.9"
             PIHOLE_DNS_2="149.112.112.112"
             ;;
         FamilyShield)
-            echo "FamilyShield servers"
+            printf "FamilyShield servers\\n"
             PIHOLE_DNS_1="208.67.222.123"
             PIHOLE_DNS_2="208.67.220.123"
             ;;
         Cloudflare)
-            echo "Cloudflare servers"
+            printf "Cloudflare servers\\n"
             PIHOLE_DNS_1="1.1.1.1"
             PIHOLE_DNS_2="1.0.0.1"
             ;;
@@ -939,10 +942,13 @@ setDNS() {
 
                 # Dialog for the user to enter custom upstream servers
                 piholeDNS=$(whiptail --backtitle "Specify Upstream DNS Provider(s)"  --inputbox "Enter your desired upstream DNS provider(s), separated by a comma.\\n\\nFor example '8.8.8.8, 8.8.4.4'" ${r} ${c} "${prePopulate}" 3>&1 1>&2 2>&3) || \
-                { echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
-                #
-                PIHOLE_DNS_1=$(echo "${piholeDNS}" | sed 's/[, \t]\+/,/g' | awk -F, '{print$1}')
-                PIHOLE_DNS_2=$(echo "${piholeDNS}" | sed 's/[, \t]\+/,/g' | awk -F, '{print$2}')
+                { printf "  %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
+                # Clean user input and replace whitespace with comma.
+                piholeDNS=$(sed 's/[, \t]\+/,/g' <<< "${piholeDNS}")
+
+                printf -v PIHOLE_DNS_1 "${piholeDNS%%,*}"
+                printf -v PIHOLE_DNS_2 "${piholeDNS##*,}"
+
                 # If the IP is valid,
                 if ! valid_ip "${PIHOLE_DNS_1}" || [[ ! "${PIHOLE_DNS_1}" ]]; then
                     # store it in the variable so we can use it
@@ -995,17 +1001,17 @@ setLogging() {
     LogChooseOptions=("On (Recommended)" "" on
         Off "" off)
     # Get the user's choice
-    LogChoices=$("${LogToggleCommand[@]}" "${LogChooseOptions[@]}" 2>&1 >/dev/tty) || (echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}" && exit 1)
+    LogChoices=$("${LogToggleCommand[@]}" "${LogChooseOptions[@]}" 2>&1 >/dev/tty) || (printf "  %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" && exit 1)
     case ${LogChoices} in
         # If it's on
         "On (Recommended)")
-            echo -e "  ${INFO} Logging On."
+            printf "  %b Logging On.\\n" "${INFO}"
             # Set the GLOBAL variable to true so we know what they selected
             QUERY_LOGGING=true
             ;;
         # Otherwise, it's off,
         Off)
-            echo -e "  ${INFO} Logging Off."
+            printf "  %b Logging Off.\\n" "${INFO}"
             # So set it to false
             QUERY_LOGGING=false
             ;;
@@ -1024,16 +1030,16 @@ setAdminFlag() {
     # with the default being enabled
     WebChooseOptions=("On (Recommended)" "" on
         Off "" off)
-    WebChoices=$("${WebToggleCommand[@]}" "${WebChooseOptions[@]}" 2>&1 >/dev/tty) || (echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}" && exit 1)
+    WebChoices=$("${WebToggleCommand[@]}" "${WebChooseOptions[@]}" 2>&1 >/dev/tty) || (printf "  %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" && exit 1)
     # Depending on their choice
     case ${WebChoices} in
         "On (Recommended)")
-            echo -e "  ${INFO} Web Interface On"
+            printf "  %b Web Interface On\\n" "${INFO}"
             # Set it to true
             INSTALL_WEB_INTERFACE=true
             ;;
         Off)
-            echo -e "  ${INFO} Web Interface Off"
+            printf "  %b Web Interface Off\\n" "${INFO}"
             # or false
             INSTALL_WEB_INTERFACE=false
             ;;
@@ -1045,16 +1051,16 @@ setAdminFlag() {
         # with the default being enabled
         WebChooseOptions=("On (Recommended)" "" on
             Off "" off)
-        WebChoices=$("${WebToggleCommand[@]}" "${WebChooseOptions[@]}" 2>&1 >/dev/tty) || (echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}" && exit 1)
+        WebChoices=$("${WebToggleCommand[@]}" "${WebChooseOptions[@]}" 2>&1 >/dev/tty) || (printf "  %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" && exit 1)
         # Depending on their choice
         case ${WebChoices} in
             "On (Recommended)")
-                echo -e "  ${INFO} Web Server On"
+                printf "  %b Web Server On\\n" "${INFO}"
                 # set it to true, as clearly seen below.
                 INSTALL_WEB_SERVER=true
                 ;;
             Off)
-                echo -e "  ${INFO} Web Server Off"
+                printf "  %b Web Server Off\\n" "${INFO}"
                 # or false
                 INSTALL_WEB_SERVER=false
                 ;;
@@ -1080,7 +1086,7 @@ chooseBlocklists() {
         HostsFile "Hosts-file.net Ads" on)
 
     # In a variable, show the choices available; exit if Cancel is selected
-    choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty) || { echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; rm "${adlistFile}" ;exit 1; }
+    choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty) || { printf "  %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; rm "${adlistFile}" ;exit 1; }
     # For each choice available,
     for choice in ${choices}
     do
@@ -1132,39 +1138,39 @@ version_check_dnsmasq() {
 
     # If the dnsmasq config file exists
     if [[ -f "${dnsmasq_conf}" ]]; then
-        echo -ne "  ${INFO} Existing dnsmasq.conf found..."
+        printf "  %b Existing dnsmasq.conf found..." "${INFO}"
         # If gravity.list is found within this file, we presume it's from older versions on Pi-hole,
         if grep -q ${dnsmasq_pihole_id_string} ${dnsmasq_conf}; then
-            echo " it is from a previous Pi-hole install."
-            echo -ne "  ${INFO} Backing up dnsmasq.conf to dnsmasq.conf.orig..."
+            printf " it is from a previous Pi-hole install.\\n"
+            printf "  %b Backing up dnsmasq.conf to dnsmasq.conf.orig..." "${INFO}"
             # so backup the original file
             mv -f ${dnsmasq_conf} ${dnsmasq_conf_orig}
-            echo -e "${OVER}  ${TICK} Backing up dnsmasq.conf to dnsmasq.conf.orig..."
-            echo -ne "  ${INFO} Restoring default dnsmasq.conf..."
+            printf "%b  %b Backing up dnsmasq.conf to dnsmasq.conf.orig...\\n" "${OVER}"  "${TICK}"
+            printf "  %b Restoring default dnsmasq.conf..." "${INFO}"
             # and replace it with the default
             cp ${dnsmasq_original_config} ${dnsmasq_conf}
-            echo -e "${OVER}  ${TICK} Restoring default dnsmasq.conf..."
+            printf "%b  %b Restoring default dnsmasq.conf...\\n" "${OVER}"  "${TICK}"
         # Otherwise,
         else
         # Don't to anything
-        echo " it is not a Pi-hole file, leaving alone!"
+        printf " it is not a Pi-hole file, leaving alone!\\n"
         fi
     else
         # If a file cannot be found,
-        echo -ne "  ${INFO} No dnsmasq.conf found... restoring default dnsmasq.conf..."
+        printf "  %b No dnsmasq.conf found... restoring default dnsmasq.conf..." "${INFO}"
         # restore the default one
         cp ${dnsmasq_original_config} ${dnsmasq_conf}
-        echo -e "${OVER}  ${TICK} No dnsmasq.conf found... restoring default dnsmasq.conf..."
+        printf "%b  %b No dnsmasq.conf found... restoring default dnsmasq.conf...\\n" "${OVER}"  "${TICK}"
     fi
 
-    echo -en "  ${INFO} Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf..."
+    printf "  %b Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf..." "${INFO}"
     # Check to see if dnsmasq directory exists (it may not due to being a fresh install and dnsmasq no longer being a dependency)
     if [[ ! -d "/etc/dnsmasq.d"  ]];then
         mkdir "/etc/dnsmasq.d"
     fi
     # Copy the new Pi-hole DNS config file into the dnsmasq.d directory
     cp ${dnsmasq_pihole_01_snippet} ${dnsmasq_pihole_01_location}
-    echo -e "${OVER}  ${TICK} Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf"
+    printf "%b  %b Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf\\n" "${OVER}"  "${TICK}"
     # Replace our placeholder values with the GLOBAL DNS variables that we populated earlier
     # First, swap in the interface to listen on
     sed -i "s/@INT@/$PIHOLE_INTERFACE/" ${dnsmasq_pihole_01_location}
@@ -1218,7 +1224,7 @@ clean_existing() {
 installScripts() {
     # Local, named variables
     local str="Installing scripts from ${PI_HOLE_LOCAL_REPO}"
-    echo -ne "  ${INFO} ${str}..."
+    printf "  %b %s..." "${INFO}" "${str}"
 
     # Clear out script files from Pi-hole scripts directory.
     clean_existing "${PI_HOLE_INSTALL_DIR}" "${PI_HOLE_FILES[@]}"
@@ -1240,27 +1246,26 @@ installScripts() {
         install -o "${USER}" -Dm755 -t "${PI_HOLE_INSTALL_DIR}" ./advanced/Scripts/COL_TABLE
         install -o "${USER}" -Dm755 -t /usr/local/bin/ pihole
         install -Dm644 ./advanced/bash-completion/pihole /etc/bash_completion.d/pihole
-        echo -e "${OVER}  ${TICK} ${str}"
+        printf "%b  %b %s\\n" "${OVER}" "${TICK}" "${str}"
 
     # Otherwise,
     else
         # Show an error and exit
-        echo -e "${OVER}  ${CROSS} ${str}
-        ${COL_LIGHT_RED}Error: Local repo ${PI_HOLE_LOCAL_REPO} not found, exiting installer${COL_NC}"
+        printf "%b  %b %s\\n" "${OVER}"  "${CROSS}" "${str}"
+        printf "\t\t%bError: Local repo %s not found, exiting installer%b\\n" "${COL_LIGHT_RED}" "${PI_HOLE_LOCAL_REPO}" "${COL_NC}"
         return 1
     fi
 }
 
 # Install the configs from PI_HOLE_LOCAL_REPO to their various locations
 installConfigs() {
-    echo ""
-    echo -e "  ${INFO} Installing configs from ${PI_HOLE_LOCAL_REPO}..."
+    printf "\\n  %b Installing configs from %s...\\n" "${INFO}" "${PI_HOLE_LOCAL_REPO}"
     # Make sure Pi-hole's config files are in place
     version_check_dnsmasq
     # Install empty file if it does not exist
     if [[ ! -f "${PI_HOLE_CONFIG_DIR}/pihole-FTL.conf" ]]; then
         if ! install -o pihole -g pihole -m 664 /dev/null "${PI_HOLE_CONFIG_DIR}/pihole-FTL.conf" &>/dev/null; then
-            echo -e "  ${COL_LIGHT_RED}Error: Unable to initialize configuration file ${PI_HOLE_CONFIG_DIR}/pihole-FTL.conf"
+            printf "  %bError: Unable to initialize configuration file %s/pihole-FTL.conf\\n" "${COL_LIGHT_RED}" "${PI_HOLE_CONFIG_DIR}"
             return 1
         fi
     fi
@@ -1304,14 +1309,14 @@ install_manpage() {
     # Copy Pi-hole man pages and call mandb to update man page database
     # Default location for man files for /usr/local/bin is /usr/local/share/man
     # on lightweight systems may not be present, so check before copying.
-    echo -en "  ${INFO} Testing man page installation"
+    printf "  %b Testing man page installation" "${INFO}"
     if ! command -v mandb &>/dev/null; then
         # if mandb is not present, no manpage support
-        echo -e "${OVER}  ${INFO} man not installed"
+        printf "%b  %b man not installed\\n" "${OVER}" "${INFO}"
         return
     elif [[ ! -d "/usr/local/share/man" ]]; then
         # appropriate directory for Pi-hole's man page is not present
-        echo -e "${OVER}  ${INFO} man pages not installed"
+        printf "%b  %b man pages not installed\\n" "${OVER}" "${INFO}"
         return
     fi
     if [[ ! -d "/usr/local/share/man/man8" ]]; then
@@ -1328,13 +1333,13 @@ install_manpage() {
     cp ${PI_HOLE_LOCAL_REPO}/manpages/pihole-FTL.conf.5 /usr/local/share/man/man5/pihole-FTL.conf.5
     if mandb -q &>/dev/null; then
         # Updated successfully
-        echo -e "${OVER}  ${TICK} man pages installed and database updated"
+        printf "%b  %b man pages installed and database updated\\n" "${OVER}" "${TICK}"
         return
     else
         # Something is wrong with the system's man installation, clean up
         # our files, (leave everything how we found it).
         rm /usr/local/share/man/man8/pihole.8 /usr/local/share/man/man8/pihole-FTL.8 /usr/local/share/man/man5/pihole-FTL.conf.5
-        echo -e "${OVER}  ${CROSS} man page db not updated, man pages not installed"
+        printf "%b  %b man page db not updated, man pages not installed\\n" "${OVER}" "${CROSS}"
     fi
 }
 
@@ -1342,20 +1347,20 @@ stop_service() {
     # Stop service passed in as argument.
     # Can softfail, as process may not be installed when this is called
     local str="Stopping ${1} service"
-    echo -ne "  ${INFO} ${str}..."
+    printf "  %b %s..." "${INFO}" "${str}"
     if command -v systemctl &> /dev/null; then
         systemctl stop "${1}" &> /dev/null || true
     else
         service "${1}" stop &> /dev/null || true
     fi
-    echo -e "${OVER}  ${TICK} ${str}..."
+    printf "%b  %b %s...\\n" "${OVER}" "${TICK}" "${str}"
 }
 
 # Start/Restart service passed in as argument
 start_service() {
     # Local, named variables
     local str="Starting ${1} service"
-    echo -ne "  ${INFO} ${str}..."
+    printf "  %b %s..." "${INFO}" "${str}"
     # If systemctl exists,
     if command -v systemctl &> /dev/null; then
         # use that to restart the service
@@ -1365,14 +1370,14 @@ start_service() {
         # fall back to the service command
         service "${1}" restart &> /dev/null
     fi
-    echo -e "${OVER}  ${TICK} ${str}"
+    printf "%b  %b %s...\\n" "${OVER}" "${TICK}" "${str}"
 }
 
 # Enable service so that it will start with next reboot
 enable_service() {
     # Local, named variables
     local str="Enabling ${1} service to start on reboot"
-    echo -ne "  ${INFO} ${str}..."
+    printf "  %b %s..." "${INFO}" "${str}"
     # If systemctl exists,
     if command -v systemctl &> /dev/null; then
         # use that to enable the service
@@ -1382,14 +1387,14 @@ enable_service() {
         # use update-rc.d to accomplish this
         update-rc.d "${1}" defaults &> /dev/null
     fi
-    echo -e "${OVER}  ${TICK} ${str}"
+    printf "%b  %b %s...\\n" "${OVER}" "${TICK}" "${str}"
 }
 
 # Disable service so that it will not with next reboot
 disable_service() {
     # Local, named variables
     local str="Disabling ${1} service"
-    echo -ne "  ${INFO} ${str}..."
+    printf "  %b %s..." "${INFO}" "${str}"
     # If systemctl exists,
     if command -v systemctl &> /dev/null; then
         # use that to disable the service
@@ -1399,7 +1404,7 @@ disable_service() {
         # use update-rc.d to accomplish this
         update-rc.d "${1}" disable &> /dev/null
     fi
-    echo -e "${OVER}  ${TICK} ${str}"
+    printf "%b  %b %s...\\n" "${OVER}" "${TICK}" "${str}"
 }
 
 check_service_active() {
@@ -1416,25 +1421,25 @@ check_service_active() {
 
 # Systemd-resolved's DNSStubListener and dnsmasq can't share port 53.
 disable_resolved_stublistener() {
-    echo -en "  ${INFO} Testing if systemd-resolved is enabled"
+    printf "  %b Testing if systemd-resolved is enabled\\n" "${INFO}"
     # Check if Systemd-resolved's DNSStubListener is enabled and active on port 53
     if check_service_active "systemd-resolved"; then
         # Check if DNSStubListener is enabled
-        echo -en "  ${OVER}  ${INFO} Testing if systemd-resolved DNSStub-Listener is active"
+        printf "  %b  %b Testing if systemd-resolved DNSStub-Listener is active" "${OVER}" "${INFO}"
         if ( grep -E '#?DNSStubListener=yes' /etc/systemd/resolved.conf &> /dev/null ); then
             # Disable the DNSStubListener to unbind it from port 53
             # Note that this breaks dns functionality on host until dnsmasq/ftl are up and running
-            echo -en "${OVER}  ${TICK} Disabling systemd-resolved DNSStubListener"
+            printf "%b  %b Disabling systemd-resolved DNSStubListener" "${OVER}" "${TICK}"
             # Make a backup of the original /etc/systemd/resolved.conf
             # (This will need to be restored on uninstallation)
             sed -r -i.orig 's/#?DNSStubListener=yes/DNSStubListener=no/g' /etc/systemd/resolved.conf
-            echo -e " and restarting systemd-resolved"
+            printf " and restarting systemd-resolved\\n"
             systemctl reload-or-restart systemd-resolved
         else
-            echo -e "${OVER}  ${INFO} Systemd-resolved does not need to be restarted"
+            printf "%b  %b Systemd-resolved does not need to be restarted\\n" "${OVER}" "${INFO}"
         fi
     else
-        echo -e "${OVER}  ${INFO} Systemd-resolved is not enabled"
+        printf "%b  %b Systemd-resolved is not enabled\\n" "${OVER}" "${INFO}"
     fi
 }
 
@@ -1447,16 +1452,15 @@ update_package_cache() {
 
     # Local, named variables
     local str="Update local cache of available packages"
-    echo ""
-    echo -ne "  ${INFO} ${str}..."
+    printf "  %b %s..." "${INFO}" "${str}"
     # Create a command from the package cache variable
     if eval "${UPDATE_PKG_CACHE}" &> /dev/null; then
-        echo -e "${OVER}  ${TICK} ${str}"
+        printf "%b  %b %s\\n" "${OVER}" "${TICK}" "${str}"
     # Otherwise,
     else
         # show an error and exit
-        echo -e "${OVER}  ${CROSS} ${str}"
-        echo -ne "  ${COL_LIGHT_RED}Error: Unable to update package cache. Please try \"${UPDATE_PKG_CACHE}\"${COL_NC}"
+        printf "%b  %b %s\\n" "${OVER}" "${CROSS}" "${str}"
+        printf "  %bError: Unable to update package cache. Please try \"%s\"%b" "${COL_LIGHT_RED}" "${COL_LIGHT_RED}" "${COL_NC}"
         return 1
     fi
 }
@@ -1466,22 +1470,20 @@ update_package_cache() {
 notify_package_updates_available() {
     # Local, named variables
     local str="Checking ${PKG_MANAGER} for upgraded packages"
-    echo -ne "\\n  ${INFO} ${str}..."
+    printf "\\n  %b %s..." "${INFO}" "${str}"
     # Store the list of packages in a variable
     updatesToInstall=$(eval "${PKG_COUNT}")
 
     if [[ -d "/lib/modules/$(uname -r)" ]]; then
         if [[ "${updatesToInstall}" -eq 0 ]]; then
-            echo -e "${OVER}  ${TICK} ${str}... up to date!"
-            echo ""
+            printf "%b  %b %s... up to date!\\n\\n" "${OVER}" "${TICK}" "${str}"
         else
-            echo -e "${OVER}  ${TICK} ${str}... ${updatesToInstall} updates available"
-            echo -e "  ${INFO} ${COL_LIGHT_GREEN}It is recommended to update your OS after installing the Pi-hole! ${COL_NC}"
-            echo ""
+            printf "%b  %b %s... %s updates available\\n" "${OVER}" "${TICK}" "${str}" "${updatesToInstall}"
+            printf "  %b %bIt is recommended to update your OS after installing the Pi-hole!%b\\n\\n" "${INFO}" "${COL_LIGHT_GREEN}" "${COL_NC}"
         fi
     else
-        echo -e "${OVER}  ${CROSS} ${str}
-        Kernel update detected. If the install fails, please reboot and try again\\n"
+        printf "%b  %b %s\\n" "${OVER}" "${CROSS}" "${str}"
+        printf "      Kernel update detected. If the install fails, please reboot and try again\\n"
     fi
 }
 
@@ -1495,10 +1497,10 @@ install_dependent_packages() {
     # If it equals 1,
     if [[ "${counter}" == 1 ]]; then
         #
-        echo -e "  ${INFO} Installer Dependency checks..."
+        printf "  %b Installer Dependency checks...\\n" "${INFO}"
     else
         #
-        echo -e "  ${INFO} Main Dependency checks..."
+        printf "  %b Main Dependency checks...\\n" "${INFO}"
     fi
 
     # Install packages passed in via argument array
@@ -1514,9 +1516,9 @@ install_dependent_packages() {
     if command -v debconf-apt-progress &> /dev/null; then
         # For each package,
         for i in "${argArray1[@]}"; do
-            echo -ne "  ${INFO} Checking for $i..."
+            printf "  %b Checking for %s..." "${INFO}" "${i}"
             if dpkg-query -W -f='${Status}' "${i}" 2>/dev/null | grep "ok installed" &> /dev/null; then
-                echo -e "${OVER}  ${TICK} Checking for $i"
+                printf "%b  %b Checking for %s\\n" "${OVER}" "${TICK}" "${i}"
             else
                 echo -e "${OVER}  ${INFO} Checking for $i (will be installed)"
                 installArray+=("${i}")
@@ -1527,17 +1529,17 @@ install_dependent_packages() {
             debconf-apt-progress -- "${PKG_INSTALL[@]}" "${installArray[@]}"
             return
         fi
-        echo ""
+        printf "\\n"
         return 0
     fi
 
     # Install Fedora/CentOS packages
     for i in "${argArray1[@]}"; do
-        echo -ne "  ${INFO} Checking for $i..."
+        printf "  %b Checking for %s..." "${INFO}" "${i}"
         if ${PKG_MANAGER} -q list installed "${i}" &> /dev/null; then
-            echo -e "${OVER}  ${TICK} Checking for $i"
+            printf "%b  %b Checking for %s" "${OVER}" "${TICK}" "${i}"
         else
-            echo -e "${OVER}  ${INFO} Checking for $i (will be installed)"
+            printf "%b  %b Checking for %s (will be installed)" "${OVER}" "${INFO}" "${i}"
             installArray+=("${i}")
         fi
     done
@@ -1545,17 +1547,16 @@ install_dependent_packages() {
         "${PKG_INSTALL[@]}" "${installArray[@]}" &> /dev/null
         return
     fi
-    echo ""
+    printf "\\n"
     return 0
 }
 
 # Install the Web interface dashboard
 installPiholeWeb() {
-    echo ""
-    echo "  ${INFO} Installing blocking page..."
+    printf "\\n  %b Installing blocking page...\\n" "${INFO}"
 
     local str="Creating directory for blocking page, and copying files"
-    echo -ne "  ${INFO} ${str}..."
+    printf "  %b %s..." "${INFO}" "${str}"
     # Install the directory
     install -d /var/www/html/pihole
     # and the blockpage
@@ -1566,26 +1567,25 @@ installPiholeWeb() {
         rm "/var/www/html/pihole/index.js"
     fi
 
-    echo -e "${OVER}  ${TICK} ${str}"
+    printf "%b  %b %s\\n" "${OVER}" "${TICK}" "${str}"
 
     local str="Backing up index.lighttpd.html"
-    echo -ne "  ${INFO} ${str}..."
+    printf "  %b %s..." "${INFO}" "${str}"
     # If the default index file exists,
     if [[ -f "/var/www/html/index.lighttpd.html" ]]; then
         # back it up
         mv /var/www/html/index.lighttpd.html /var/www/html/index.lighttpd.orig
-        echo -e "${OVER}  ${TICK} ${str}"
+        printf "%b  %b %s\\n" "${OVER}" "${TICK}" "${str}"
     # Otherwise,
     else
         # don't do anything
-        echo -e "${OVER}  ${CROSS} ${str}
-        No default index.lighttpd.html file found... not backing up"
+        printf "%b  %b %s\\n" "${OVER}" "${CROSS}" "${str}"
+        printf "      No default index.lighttpd.html file found... not backing up\\n"
     fi
 
     # Install Sudoers file
-    echo ""
     local str="Installing sudoer file"
-    echo -ne "  ${INFO} ${str}..."
+    printf "\\n  %b %s..." "${INFO}" "${str}"
     # Make the .d directory if it doesn't exist
     mkdir -p /etc/sudoers.d/
     # and copy in the pihole sudoers file
@@ -1601,22 +1601,21 @@ installPiholeWeb() {
     fi
     # Set the strict permissions on the file
     chmod 0440 /etc/sudoers.d/pihole
-    echo -e "${OVER}  ${TICK} ${str}"
+    printf "%b  %b %s\\n" "${OVER}" "${TICK}" "${str}"
 }
 
 # Installs a cron file
 installCron() {
     # Install the cron job
     local str="Installing latest Cron script"
-    echo ""
-    echo -ne "  ${INFO} ${str}..."
+    printf "\\n  %b %s..." "${INFO}" "${str}"
     # Copy the cron file over from the local repo
     cp ${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole.cron /etc/cron.d/pihole
     # Randomize gravity update time
     sed -i "s/59 1 /$((1 + RANDOM % 58)) $((3 + RANDOM % 2))/" /etc/cron.d/pihole
     # Randomize update checker time
     sed -i "s/59 17/$((1 + RANDOM % 58)) $((12 + RANDOM % 8))/" /etc/cron.d/pihole
-    echo -e "${OVER}  ${TICK} ${str}"
+    printf "%b  %b %s\\n" "${OVER}" "${TICK}" "${str}"
 }
 
 # Gravity is a very important script as it aggregates all of the domains into a single HOSTS formatted list,
@@ -1629,34 +1628,34 @@ runGravity() {
 # Check if the pihole user exists and create if it does not
 create_pihole_user() {
     local str="Checking for user 'pihole'"
-    echo -ne "  ${INFO} ${str}..."
+    printf "  %b %s..." "${INFO}" "${str}"
     # If the user pihole exists,
     if id -u pihole &> /dev/null; then
         # just show a success
-        echo -e "${OVER}  ${TICK} ${str}"
+        printf "%b  %b %s\\n" "${OVER}" "${TICK}" "${str}"
     # Otherwise,
     else
-        echo -ne "${OVER}  ${CROSS} ${str}"
+        printf "%b  %b %s" "${OVER}" "${CROSS}" "${str}"
         local str="Creating user 'pihole'"
-        echo -ne "${OVER}  ${INFO} ${str}..."
+        printf "%b  %b %s..." "${OVER}" "${INFO}" "${str}"
         # create her with the useradd command
         if useradd -r -s /usr/sbin/nologin pihole; then
-          echo -e "${OVER}  ${TICK} ${str}"
+          printf "%b  %b %s\\n" "${OVER}" "${TICK}" "${str}"
         else
-          echo -e "${OVER}  ${CROSS} ${str}"
+          printf "%b  %b %s\\n" "${OVER}" "${CROSS}" "${str}"
         fi
     fi
 }
 
 # Allow HTTP and DNS traffic
 configureFirewall() {
-    echo ""
+    printf "\\n"
     # If a firewall is running,
     if firewall-cmd --state &> /dev/null; then
         # ask if the user wants to install Pi-hole's default firewall rules
         whiptail --title "Firewall in use" --yesno "We have detected a running firewall\\n\\nPi-hole currently requires HTTP and DNS port access.\\n\\n\\n\\nInstall Pi-hole default firewall rules?" ${r} ${c} || \
-        { echo -e "  ${INFO} Not installing firewall rulesets."; return 0; }
-        echo -e "  ${TICK} Configuring FirewallD for httpd and pihole-FTL"
+        { printf "  %b Not installing firewall rulesets.\\n" "${INFO}"; return 0; }
+        printf "  %b Configuring FirewallD for httpd and pihole-FTL\\n" "${TICK}"
         # Allow HTTP and DNS traffic
         firewall-cmd --permanent --add-service=http --add-service=dns
         # Reload the firewall to apply these changes
@@ -1668,8 +1667,8 @@ configureFirewall() {
     # then check and insert our Rules above the DROP/REJECT Rule.
         if iptables -S INPUT | head -n1 | grep -qv '^-P.*ACCEPT$' || iptables -S INPUT | tail -n1 | grep -qv '^-\(A\|P\).*ACCEPT$'; then
             whiptail --title "Firewall in use" --yesno "We have detected a running firewall\\n\\nPi-hole currently requires HTTP and DNS port access.\\n\\n\\n\\nInstall Pi-hole default firewall rules?" ${r} ${c} || \
-            { echo -e "  ${INFO} Not installing firewall rulesets."; return 0; }
-            echo -e "  ${TICK} Installing new IPTables firewall rulesets"
+            { printf "  %b Not installing firewall rulesets.\\n" "${INFO}"; return 0; }
+            printf "  %b Installing new IPTables firewall rulesets\\n" "${TICK}"
             # Check chain first, otherwise a new rule will duplicate old ones
             iptables -C INPUT -p tcp -m tcp --dport 80 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 80 -j ACCEPT
             iptables -C INPUT -p tcp -m tcp --dport 53 -j ACCEPT &> /dev/null || iptables -I INPUT 1 -p tcp -m tcp --dport 53 -j ACCEPT
@@ -1680,11 +1679,11 @@ configureFirewall() {
     # Otherwise,
     else
         # no firewall is running
-        echo -e "  ${INFO} No active firewall detected.. skipping firewall configuration"
+        printf "  %b No active firewall detected.. skipping firewall configuration\\n" "${INFO}"
         # so just exit
         return 0
     fi
-    echo -e "  ${INFO} Skipping firewall configuration"
+    printf "  %b Skipping firewall configuration\\n" "${INFO}"
 }
 
 #
@@ -1735,8 +1734,7 @@ finalExports() {
 installLogrotate() {
 
     local str="Installing latest logrotate script"
-    echo ""
-    echo -ne "  ${INFO} ${str}..."
+    printf "\\n  %b %s..." "${INFO} ${str}"
     # Copy the file over from the local repo
     cp ${PI_HOLE_LOCAL_REPO}/advanced/Templates/logrotate /etc/pihole/logrotate
     # Different operating systems have different user / group
@@ -1751,7 +1749,7 @@ installLogrotate() {
         #
         sed -i "s/# su #/su ${logusergroup}/g;" /etc/pihole/logrotate
     fi
-    echo -e "${OVER}  ${TICK} ${str}"
+    printf "%b  %b %s\\n" "${OVER}" "${TICK}" "${str}"
 }
 
 # At some point in the future this list can be pruned, for now we'll need it to ensure updates don't break.
@@ -1799,8 +1797,8 @@ installPihole() {
                 lighty-enable-mod fastcgi fastcgi-php > /dev/null || true
             else
                 # Otherwise, show info about installing them
-                echo -e  "  ${INFO} Warning: 'lighty-enable-mod' utility not found
-                Please ensure fastcgi is enabled if you experience issues\\n"
+                printf "  %b Warning: 'lighty-enable-mod' utility not found\\n" "${INFO}"
+                printf "      Please ensure fastcgi is enabled if you experience issues\\n"
             fi
         fi
     fi
@@ -1810,12 +1808,12 @@ installPihole() {
     fi
     # Install base files and web interface
     if ! installScripts; then
-        echo -e "  {CROSS} Failure in dependent script copy function."
+        printf "  %b Failure in dependent script copy function.\\n" "${CROSS}"
         exit 1
     fi
     # Install config files
     if ! installConfigs; then
-        echo -e "  {CROSS} Failure in dependent config copy function."
+        printf "  %b Failure in dependent config copy function.\\n" "${CROSS}"
         exit 1
     fi
     # If the user wants to install the dashboard,
@@ -1828,7 +1826,7 @@ installPihole() {
     # Install the logrotate file
     installLogrotate
     # Check if FTL is installed
-    FTLdetect || echo -e "  ${CROSS} FTL Engine not installed"
+    FTLdetect || printf "  %b FTL Engine not installed\\n" "${CROSS}"
     # Configure the firewall
     if [[ "${useUpdateVars}" == false ]]; then
         configureFirewall
@@ -1847,15 +1845,15 @@ checkSelinux() {
     if command -v getenforce &> /dev/null; then
         # Store the current mode in a variable
         enforceMode=$(getenforce)
-        echo -e "\\n  ${INFO} SELinux mode detected: ${enforceMode}"
+        printf "\\n  %b SELinux mode detected: %s\\n" "${INFO}" "${enforceMode}"
 
         # If it's enforcing,
         if [[ "${enforceMode}" == "Enforcing" ]]; then
             # Explain Pi-hole does not support it yet
             whiptail --defaultno --title "SELinux Enforcing Detected" --yesno "SELinux is being ENFORCED on your system! \\n\\nPi-hole currently does not support SELinux, but you may still continue with the installation.\\n\\nNote: Web Admin will not be fully functional unless you set your policies correctly\\n\\nContinue installing Pi-hole?" ${r} ${c} || \
-            { echo -e "\\n  ${COL_LIGHT_RED}SELinux Enforcing detected, exiting installer${COL_NC}"; exit 1; }
-            echo -e "  ${INFO} Continuing installation with SELinux Enforcing
-            ${INFO} Please refer to official SELinux documentation to create a custom policy"
+            { printf "\\n  %bSELinux Enforcing detected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
+            printf "  %b Continuing installation with SELinux Enforcing\\n" "${INFO}"
+            printf "      %b Please refer to official SELinux documentation to create a custom policy\\n" "${INFO}"
         fi
     fi
 }
@@ -1915,18 +1913,18 @@ update_dialogs() {
     UpdateCmd=$(whiptail --title "Existing Install Detected!" --menu "\\n\\nWe have detected an existing install.\\n\\nPlease choose from the following options: \\n($strAdd)" ${r} ${c} 2 \
     "${opt1a}"  "${opt1b}" \
     "${opt2a}"  "${opt2b}" 3>&2 2>&1 1>&3) || \
-    { echo -e "  ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; }
+    { printf "  %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
 
     # Set the variable based on if the user chooses
     case ${UpdateCmd} in
         # repair, or
         ${opt1a})
-            echo -e "  ${INFO} ${opt1a} option selected"
+            printf "  %b %s option selected\\n" "${INFO}" "${opt1a}"
             useUpdateVars=true
             ;;
         # reconfigure,
         ${opt2a})
-            echo -e "  ${INFO} ${opt2a} option selected"
+            printf "  %b %s option selected\\n" "${INFO}" "${opt2a}"
             useUpdateVars=false
             ;;
     esac
@@ -1964,6 +1962,7 @@ get_available_branches() {
     cd "${directory}" || return 1
     # Get reachable remote branches, but store STDERR as STDOUT variable
     output=$( { git ls-remote --heads --quiet | cut -d'/' -f3- -; } 2>&1 )
+    # echo status for calling function to capture
     echo "$output"
     return
 }
@@ -1997,16 +1996,16 @@ checkout_pull_branch() {
     oldbranch="$(git symbolic-ref HEAD)"
 
     str="Switching to branch: '${branch}' from '${oldbranch}'"
-    echo -ne "  ${INFO} $str"
+    printf "  %b %s" "${INFO}" "$str"
     git checkout "${branch}" --quiet || return 1
-    echo -e "${OVER}  ${TICK} $str"
+    printf "%b  %b %s\\n" "${OVER}" "${TICK}" "$str"
 
     git_pull=$(git pull || return 1)
 
     if [[ "$git_pull" == *"up-to-date"* ]]; then
-        echo -e "  ${INFO} ${git_pull}"
+        printf "  %b %s\\n" "${INFO}" "${git_pull}"
     else
-        echo -e "$git_pull\\n"
+        printf "%s\\n" "$git_pull"
     fi
 
     return 0
@@ -2015,17 +2014,17 @@ checkout_pull_branch() {
 clone_or_update_repos() {
     # If the user wants to reconfigure,
     if [[ "${reconfigure}" == true ]]; then
-        echo "  ${INFO} Performing reconfiguration, skipping download of local repos"
+        printf "  %b Performing reconfiguration, skipping download of local repos\\n" "${INFO}"
         # Reset the Core repo
         resetRepo ${PI_HOLE_LOCAL_REPO} || \
-        { echo -e "  ${COL_LIGHT_RED}Unable to reset ${PI_HOLE_LOCAL_REPO}, exiting installer${COL_NC}"; \
+        { printf "  %bUnable to reset %s, exiting installer%b\\n" "${COL_LIGHT_RED}" "${PI_HOLE_LOCAL_REPO}" "${COL_NC}"; \
         exit 1; \
         }
         # If the Web interface was installed,
         if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
             # reset it's repo
             resetRepo ${webInterfaceDir} || \
-            { echo -e "  ${COL_LIGHT_RED}Unable to reset ${webInterfaceDir}, exiting installer${COL_NC}"; \
+            { printf "  %bUnable to reset %s, exiting installer%b\\n" "${COL_LIGHT_RED}" "${webInterfaceDir}" "${COL_NC}"; \
             exit 1; \
             }
         fi
@@ -2033,14 +2032,14 @@ clone_or_update_repos() {
     else
         # so get git files for Core
         getGitFiles ${PI_HOLE_LOCAL_REPO} ${piholeGitUrl} || \
-        { echo -e "  ${COL_LIGHT_RED}Unable to clone ${piholeGitUrl} into ${PI_HOLE_LOCAL_REPO}, unable to continue${COL_NC}"; \
+        { printf "  %bUnable to clone %s into %s, unable to continue%b\\n" "${COL_LIGHT_RED}" "${piholeGitUrl}" "${PI_HOLE_LOCAL_REPO}" "${COL_NC}"; \
         exit 1; \
         }
         # If the Web interface was installed,
         if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
             # get the Web git files
             getGitFiles ${webInterfaceDir} ${webInterfaceGitUrl} || \
-            { echo -e "  ${COL_LIGHT_RED}Unable to clone ${webInterfaceGitUrl} into ${webInterfaceDir}, exiting installer${COL_NC}"; \
+            { printf "  %bUnable to clone %s into ${webInterfaceDir}, exiting installer%b\\n" "${COL_LIGHT_RED}" "${webInterfaceGitUrl}" "${COL_NC}"; \
             exit 1; \
             }
         fi
@@ -2053,19 +2052,19 @@ FTLinstall() {
     local binary="${1}"
     local latesttag
     local str="Downloading and Installing FTL"
-    echo -ne "  ${INFO} ${str}..."
+    printf "  %b %s..." "${INFO}" "${str}"
 
     # Find the latest version tag for FTL
     latesttag=$(curl -sI https://github.com/pi-hole/FTL/releases/latest | grep "Location" | awk -F '/' '{print $NF}')
     # Tags should always start with v, check for that.
     if [[ ! "${latesttag}" == v* ]]; then
-        echo -e "${OVER}  ${CROSS} ${str}"
-        echo -e "  ${COL_LIGHT_RED}Error: Unable to get latest release location from GitHub${COL_NC}"
+        printf "%b  %b %s\\n" "${OVER}" "${CROSS}" "${str}"
+        printf "  %bError: Unable to get latest release location from GitHub%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
         return 1
     fi
 
     # Move into the temp ftl directory
-    pushd "$(mktemp -d)" > /dev/null || { echo "Unable to make temporary directory for FTL binary download"; return 1; }
+    pushd "$(mktemp -d)" > /dev/null || { printf "Unable to make temporary directory for FTL binary download\\n"; return 1; }
 
     # Always replace pihole-FTL.service
     install -T -m 0755 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL.service" "/etc/init.d/pihole-FTL"
@@ -2093,19 +2092,19 @@ FTLinstall() {
 
         # If we downloaded binary file (as opposed to text),
         if sha1sum --status --quiet -c "${binary}".sha1; then
-            echo -n "transferred... "
+            printf "transferred... "
             # Stop FTL
             stop_service pihole-FTL &> /dev/null
             # Install the new version with the correct permissions
             install -T -m 0755 "${binary}" /usr/bin/pihole-FTL
             # Move back into the original directory the user was in
-            popd > /dev/null || { echo "Unable to return to original directory after FTL binary download."; return 1; }
+            popd > /dev/null || { printf "Unable to return to original directory after FTL binary download.\\n"; return 1; }
             # Install the FTL service
-            echo -e "${OVER}  ${TICK} ${str}"
+            printf "%b  %b %s\\n" "${OVER}" "${TICK}" "${str}"
             # dnsmasq can now be stopped and disabled if it exists
             if which dnsmasq &> /dev/null; then
                 if check_service_active "dnsmasq";then
-                    echo "  ${INFO} FTL can now resolve DNS Queries without dnsmasq running separately"
+                    printf "  %b FTL can now resolve DNS Queries without dnsmasq running separately\\n" "${INFO}"
                     stop_service dnsmasq
                     disable_service dnsmasq
                 fi
@@ -2115,7 +2114,7 @@ FTLinstall() {
             # /etc/dnsmasq.conf contains only "conf-dir=/etc/dnsmasq.d"
             local conffile="/etc/dnsmasq.conf"
             if [[ -f "${conffile}" ]]; then
-                echo "  ${INFO} Backing up ${conffile} to ${conffile}.old"
+                printf "  %b Backing up %s to %s.old\\n" "${INFO}" "${conffile}" "${conffile}"
                 mv "${conffile}" "${conffile}.old"
             fi
             # Create /etc/dnsmasq.conf
@@ -2125,17 +2124,17 @@ FTLinstall() {
         # Otherwise,
         else
             # the download failed, so just go back to the original directory
-            popd > /dev/null || { echo "Unable to return to original directory after FTL binary download."; return 1; }
-            echo -e "${OVER}  ${CROSS} ${str}"
-            echo -e "  ${COL_LIGHT_RED}Error: Download of ${url}/${binary} failed (checksum error)${COL_NC}"
+            popd > /dev/null || { printf "Unable to return to original directory after FTL binary download.\\n"; return 1; }
+            printf "%b  %b %s\\n" "${OVER}" "${CROSS}" "${str}"
+            printf "  %bError: Download of %s/%s failed (checksum error)%b\\n" "${COL_LIGHT_RED}" "${url}" "${binary}" "${COL_NC}"
             return 1
         fi
     # Otherwise,
     else
-        popd > /dev/null || { echo "Unable to return to original directory after FTL binary download."; return 1; }
-        echo -e "${OVER}  ${CROSS} ${str}"
+        popd > /dev/null || { printf "Unable to return to original directory after FTL binary download.\\n"; return 1; }
+        printf "%b  %b %s\\n" "${OVER}" "${CROSS}" "${str}"
         # The URL could not be found
-        echo -e "  ${COL_LIGHT_RED}Error: URL ${url}/${binary} not found${COL_NC}"
+        printf "  %bError: URL %s/%s not found%b\\n" "${COL_LIGHT_RED}" "${url}" "${binary}" "${COL_NC}"
         return 1
     fi
 }
@@ -2146,7 +2145,7 @@ get_binary_name() {
     machine=$(uname -m)
 
     local str="Detecting architecture"
-    echo -ne "  ${INFO} ${str}..."
+    printf "  %b %s..." "${INFO}" "${str}"
     # If the machine is arm or aarch
     if [[ "${machine}" == "arm"* || "${machine}" == *"aarch"* ]]; then
         # ARM
@@ -2158,24 +2157,24 @@ get_binary_name() {
         lib=$(ldd /bin/ls | grep -E '^\s*/lib' | awk '{ print $1 }')
         #
         if [[ "${lib}" == "/lib/ld-linux-aarch64.so.1" ]]; then
-            echo -e "${OVER}  ${TICK} Detected ARM-aarch64 architecture"
+            printf "%b  %b Detected ARM-aarch64 architecture\\n" "${OVER}" "${TICK}"
             # set the binary to be used
             binary="pihole-FTL-aarch64-linux-gnu"
         #
         elif [[ "${lib}" == "/lib/ld-linux-armhf.so.3" ]]; then
             #
             if [[ "${rev}" -gt 6 ]]; then
-                echo -e "${OVER}  ${TICK} Detected ARM-hf architecture (armv7+)"
+                printf "%b  %b Detected ARM-hf architecture (armv7+)\\n" "${OVER}" "${TICK}"
                 # set the binary to be used
                 binary="pihole-FTL-arm-linux-gnueabihf"
             # Otherwise,
             else
-                echo -e "${OVER}  ${TICK} Detected ARM-hf architecture (armv6 or lower) Using ARM binary"
+                printf "%b  %b Detected ARM-hf architecture (armv6 or lower) Using ARM binary\\n" "${OVER}" "${TICK}"
                 # set the binary to be used
                 binary="pihole-FTL-arm-linux-gnueabi"
             fi
         else
-            echo -e "${OVER}  ${TICK} Detected ARM architecture"
+            printf "%b  %b Detected ARM architecture\\n" "${OVER}" "${TICK}"
             # set the binary to be used
             binary="pihole-FTL-arm-linux-gnueabi"
         fi
@@ -2187,22 +2186,22 @@ get_binary_name() {
         # Special case: This is a 32 bit OS, installed on a 64 bit machine
         # -> change machine architecture to download the 32 bit executable
         if [[ "${dpkgarch}" == "i386" ]]; then
-            echo -e "${OVER}  ${TICK} Detected 32bit (i686) architecture"
+            printf "%b  %b Detected 32bit (i686) architecture\\n" "${OVER}" "${TICK}"
             binary="pihole-FTL-linux-x86_32"
         else
             # 64bit
-            echo -e "${OVER}  ${TICK} Detected x86_64 architecture"
+            printf "%b  %b Detected x86_64 architecture\\n" "${OVER}" "${TICK}"
             # set the binary to be used
             binary="pihole-FTL-linux-x86_64"
         fi
     else
         # Something else - we try to use 32bit executable and warn the user
         if [[ ! "${machine}" == "i686" ]]; then
-            echo -e "${OVER}  ${CROSS} ${str}..."
-            echo -e "  ${INFO} ${COL_LIGHT_RED}Not able to detect architecture (unknown: ${machine}), trying 32bit executable${COL_NC}"
-            echo -e "  ${INFO} Contact Pi-hole Support if you experience issues (e.g: FTL not running)"
+            printf "%b  %b %s...\\n" "${OVER}" "${CROSS}" "${str}"
+            printf "  %b %bNot able to detect architecture (unknown: %s), trying 32bit executable%b\\n" "${INFO}" "${COL_LIGHT_RED}" "${machine}" "${COL_NC}"
+            printf "  %b Contact Pi-hole Support if you experience issues (e.g: FTL not running)\\n" "${INFO}"
         else
-            echo -e "${OVER}  ${TICK} Detected 32bit (i686) architecture"
+            printf "%b  %b Detected 32bit (i686) architecture\\n" "${OVER}" "${TICK}"
         fi
         binary="pihole-FTL-linux-x86_32"
     fi
@@ -2213,7 +2212,7 @@ FTLcheckUpdate() {
 
     #In the next section we check to see if FTL is already installed (in case of pihole -r).
     #If the installed version matches the latest version, then check the installed sha1sum of the binary vs the remote sha1sum. If they do not match, then download
-    echo -e "  ${INFO} Checking for existing FTL binary..."
+    printf "  %b Checking for existing FTL binary...\\n" "${INFO}"
 
     local ftlLoc
     ftlLoc=$(which pihole-FTL 2>/dev/null)
@@ -2242,7 +2241,8 @@ FTLcheckUpdate() {
         path="${ftlBranch}/${binary}"
         # shellcheck disable=SC1090
         if ! check_download_exists "$path"; then
-            echo -e "  ${INFO} Branch \"${ftlBranch}\" is not available.\\n  ${INFO} Use ${COL_LIGHT_GREEN}pihole checkout ftl [branchname]${COL_NC} to switch to a valid branch."
+            printf "  %b Branch \"%s\" is not available.\\n" "${INFO}" "${ftlBranch}"
+            printf "  %b Use %bpihole checkout ftl [branchname]%b to switch to a valid branch.\\n" "${INFO}" "${COL_LIGHT_GREEN}" "${COL_NC}"
             return 2
         fi
 
@@ -2253,10 +2253,10 @@ FTLcheckUpdate() {
             localSha1=$(sha1sum "$(which pihole-FTL)" | cut -d ' ' -f 1)
 
             if [[ "${remoteSha1}" != "${localSha1}" ]]; then
-                echo -e "  ${INFO} Checksums do not match, downloading from ftl.pi-hole.net."
+                printf "  %b Checksums do not match, downloading from ftl.pi-hole.net.\\n" "${INFO}"
                 return 0
             else
-                echo -e "  ${INFO} Checksum of installed binary matches remote. No need to download!"
+                printf "  %b Checksum of installed binary matches remote. No need to download!\\n" "${INFO}"
                 return 1
             fi
         else
@@ -2272,16 +2272,16 @@ FTLcheckUpdate() {
             if [[ "${FTLversion}" != "${FTLlatesttag}" ]]; then
                 return 0
             else
-                echo -e "  ${INFO} Latest FTL Binary already installed (${FTLlatesttag}). Confirming Checksum..."
+                printf "  %b Latest FTL Binary already installed (%s). Confirming Checksum...\\n" "${INFO}" "${FTLlatesttag}"
 
                 remoteSha1=$(curl -sSL --fail "https://github.com/pi-hole/FTL/releases/download/${FTLversion%$'\r'}/${binary}.sha1" | cut -d ' ' -f 1)
                 localSha1=$(sha1sum "$(which pihole-FTL)" | cut -d ' ' -f 1)
 
                 if [[ "${remoteSha1}" != "${localSha1}" ]]; then
-                    echo -e "  ${INFO} Corruption detected..."
+                    printf "  %b Corruption detected...\\n" "${INFO}"
                     return 0
                 else
-                    echo -e "  ${INFO} Checksum correct. No need to download!"
+                    printf "  %b Checksum correct. No need to download!\\n" "${INFO}"
                     return 1
                 fi
             fi
@@ -2293,14 +2293,11 @@ FTLcheckUpdate() {
 
 # Detect suitable FTL binary platform
 FTLdetect() {
-    echo ""
-    echo -e "  ${INFO} FTL Checks..."
+    printf "\\n  %b FTL Checks...\\n\\n" "${INFO}"
 
     if FTLcheckUpdate ; then
         FTLinstall "${binary}" || return 1
     fi
-
-    echo ""
 }
 
 make_temporary_log() {
@@ -2325,37 +2322,37 @@ main() {
     ######## FIRST CHECK ########
     # Must be root to install
     local str="Root user check"
-    echo ""
+    printf "\\n"
 
     # If the user's id is zero,
     if [[ "${EUID}" -eq 0 ]]; then
         # they are root and all is good
-        echo -e "  ${TICK} ${str}"
+        printf "  %b %s\\n" "${TICK}" "${str}"
         # Show the Pi-hole logo so people know it's genuine since the logo and name are trademarked
         show_ascii_berry
         make_temporary_log
     # Otherwise,
     else
         # They do not have enough privileges, so let the user know
-        echo -e "  ${CROSS} ${str}"
-        echo -e "  ${INFO} ${COL_LIGHT_RED}Script called with non-root privileges${COL_NC}"
-        echo -e "  ${INFO} The Pi-hole requires elevated privileges to install and run"
-        echo -e "  ${INFO} Please check the installer for any concerns regarding this requirement"
-        echo -e "  ${INFO} Make sure to download this script from a trusted source\\n"
-        echo -ne "  ${INFO} Sudo utility check"
+        printf "  %b %s\\n" "${CROSS}" "${str}"
+        printf "  %b %bScript called with non-root privileges%b\\n" "${INFO}" "${COL_LIGHT_RED}" "${COL_NC}"
+        printf "      The Pi-hole requires elevated privileges to install and run\\n"
+        printf "      Please check the installer for any concerns regarding this requirement\\n"
+        printf "      Make sure to download this script from a trusted source\\n\\n"
+        printf "  %b Sudo utility check" "${INFO}"
 
         # If the sudo command exists,
         if command -v sudo &> /dev/null; then
-            echo -e "${OVER}  ${TICK} Sudo utility check"
+            printf "%b  %b Sudo utility check\\n" "${OVER}"  "${TICK}"
             # Download the install script and run it with admin rights
             exec curl -sSL https://raw.githubusercontent.com/pi-hole/pi-hole/master/automated%20install/basic-install.sh | sudo bash "$@"
             exit $?
         # Otherwise,
         else
             # Let them know they need to run it as root
-            echo -e "${OVER}  ${CROSS} Sudo utility check"
-            echo -e "  ${INFO} Sudo is needed for the Web Interface to run pihole commands\\n"
-            echo -e "  ${INFO} ${COL_LIGHT_RED}Please re-run this installer as root${COL_NC}"
+            printf "%b  %b Sudo utility check\\n" "${OVER}" "${CROSS}"
+            printf "  %b Sudo is needed for the Web Interface to run pihole commands\\n\\n" "${INFO}"
+            printf "  %b %bPlease re-run this installer as root${COL_NC}\\n" "${INFO}" "${COL_LIGHT_RED}"
             exit 1
         fi
     fi
@@ -2367,7 +2364,7 @@ main() {
     if [[ -f "${setupVars}" ]]; then
         # if it's running unattended,
         if [[ "${runUnattended}" == true ]]; then
-            echo -e "  ${INFO} Performing unattended setup, no whiptail dialogs will be displayed"
+            printf "  %b Performing unattended setup, no whiptail dialogs will be displayed\\n" "${INFO}"
             # Use the setup variables
             useUpdateVars=true
             # also disable debconf-apt-progress dialogs
@@ -2382,7 +2379,7 @@ main() {
     # Start the installer
     # Verify there is enough disk space for the install
     if [[ "${skipSpaceCheck}" == true ]]; then
-        echo -e "  ${INFO} Skipping free disk space verification"
+        printf"  %b Skipping free disk space verification\\n" "${INFO}"
     else
         verifyFreeDiskSpace
     fi
@@ -2481,11 +2478,11 @@ main() {
             start_service lighttpd
             enable_service lighttpd
         else
-            echo -e "  ${INFO} Lighttpd is disabled, skipping service restart"
+            printf "  %b Lighttpd is disabled, skipping service restart\\n" "${INFO}"
         fi
     fi
 
-    echo -e "  ${INFO} Restarting services..."
+    printf "  %b Restarting services...\\n" "${INFO}"
     # Start services
 
     # Enable FTL
@@ -2511,33 +2508,32 @@ main() {
         # If there is a password,
         if (( ${#pw} > 0 )) ; then
             # display the password
-            echo -e "  ${INFO} Web Interface password: ${COL_LIGHT_GREEN}${pw}${COL_NC}"
-            echo -e "  ${INFO} This can be changed using 'pihole -a -p'\\n"
+            printf "  %b Web Interface password: %b%s%b\\n" "${INFO}" "${COL_LIGHT_GREEN}" "${pw}" "${COL_NC}"
+            printf "  %b This can be changed using 'pihole -a -p'\\n\\n" "${INFO}"
         fi
     fi
 
     if [[ "${useUpdateVars}" == false ]]; then
         # If the Web interface was installed,
         if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
-            echo -e "  ${INFO} View the web interface at http://pi.hole/admin or http://${IPV4_ADDRESS%/*}/admin"
-            echo ""
+            printf "  %b View the web interface at http://pi.hole/admin or http://%s/admin\\n\\n" "${INFO}" "${IPV4_ADDRESS%/*}"
         fi
         # Explain to the user how to use Pi-hole as their DNS server
-        echo -e "  ${INFO} You may now configure your devices to use the Pi-hole as their DNS server"
-        [[ -n "${IPV4_ADDRESS%/*}" ]] && echo -e "  ${INFO} Pi-hole DNS (IPv4): ${IPV4_ADDRESS%/*}"
-        [[ -n "${IPV6_ADDRESS}" ]] && echo -e "  ${INFO} Pi-hole DNS (IPv6): ${IPV6_ADDRESS}"
-        echo -e "  ${INFO} If you set a new IP address, please restart the server running the Pi-hole"
+        printf "  %b You may now configure your devices to use the Pi-hole as their DNS server\\n" "${INFO}"
+        [[ -n "${IPV4_ADDRESS%/*}" ]] && printf "  %b Pi-hole DNS (IPv4): %s\\n" "${INFO}" "${IPV4_ADDRESS%/*}"
+        [[ -n "${IPV6_ADDRESS}" ]] && printf "  %b Pi-hole DNS (IPv6): %s\\n" "${INFO}" "${IPV6_ADDRESS}"
+        printf "  %b If you set a new IP address, please restart the server running the Pi-hole\\n" "${INFO}"
         INSTALL_TYPE="Installation"
     else
         INSTALL_TYPE="Update"
     fi
 
     # Display where the log file is
-    echo -e "\\n  ${INFO} The install log is located at: ${installLogLoc}
-    ${COL_LIGHT_GREEN}${INSTALL_TYPE} Complete! ${COL_NC}"
+    printf "\\n  %b The install log is located at: %s\\n" "${INFO}" "${installLogLoc}"
+    printf "%b%s Complete! %b\\n" "${COL_LIGHT_GREEN}" "${INSTALL_TYPE}" "${COL_NC}"
 
     if [[ "${INSTALL_TYPE}" == "Update" ]]; then
-        echo ""
+        printf "\\n"
         /usr/local/bin/pihole version --current
     fi
 }