#!/data/data/com.termux/files/usr/bin/bash

# Title:         tudo
# Description:   A wrapper script to execute commands as the
#                'Termux app (u<userid>_a<appid>)' user in the Termux
#                app, like to drop to an interactive shell for any of
#                the supported shells, or to execute shell script
#                files or their text passed as an argument.
# Homepage:      https://github.com/agnostic-apollo/tudo
# SPDX-License-Identifier: MIT
# Usage:         Run "tudo --help" for detailed list of usages.
# Bash version:  4.1 or higher
TUDO__VERSION="1.2.0"
[ "$TUDO__VERSION" = @"TUDO_PKG__VERSION"@ ] && \
TUDO__VERSION=1.0.0



if [ -z "${BASH_VERSION:-}" ]; then
    echo "The 'tudo' script must be run from a 'bash' shell."; return 64 2>/dev/null|| exit 64 # EX__USAGE
fi



##
# Function to set termux env variables.
#
# `tudo_set_termux_env_variables`
##
tudo_set_termux_env_variables() {

# Use path environment variables under the `TERMUX_` env root scope
# exported by the Termux app version `>= v0.119.0`, otherwise fallback
# to paths replaced during build time by termux-packages build
# infrastructure. If running on older app versions, or not building
# tudo with termux-packages, like for the `master` branch and GitHub
# releases, then use default path for current termux app for the
# `com.termux` package, but this will not work for termux forks.
local termux_rootfs_default="/data/data/com.termux/files"

TERMUX__LNAME="termux"
[ "$TERMUX__LNAME" = @"TERMUX__LNAME"@ ] && \
TERMUX__LNAME="termux"

TERMUX_APP__NAME="Termux"
[ "$TERMUX_APP__NAME" = @"TERMUX_APP__NAME"@ ] && \
TERMUX_APP__NAME="Termux"

TERMUX_ENV__SS_TERMUX="_"
[ "$TERMUX_ENV__SS_TERMUX" = @"TERMUX_ENV__SS_TERMUX"@ ] && \
TERMUX_ENV__SS_TERMUX="_"

TERMUX_ENV__S_TERMUX="TERMUX__"
[ "$TERMUX_ENV__S_TERMUX" = @"TERMUX_ENV__S_TERMUX"@ ] && \
TERMUX_ENV__S_TERMUX="TERMUX__"


termux_core__bash__termux_scoped_env_variable get-value "TERMUX_ROOTFS" \
    ss="$TERMUX_ENV__SS_TERMUX" "ROOTFS" r+='^((/)|((/[^/]+)+))$' "/data/data/com.termux/files" "$termux_rootfs_default" || return $?

termux_core__bash__termux_scoped_env_variable get-value "TERMUX_HOME" \
    ss="$TERMUX_ENV__SS_TERMUX" "HOME" r+='^(/[^/]+)+$' "/data/data/com.termux/files/home" "$termux_rootfs_default/home" || return $?

termux_core__bash__termux_scoped_env_variable get-value "TERMUX_PREFIX" \
    ss="$TERMUX_ENV__SS_TERMUX" "PREFIX" r+='^(/[^/]+)+$' "/data/data/com.termux/files/usr" "$termux_rootfs_default/usr" || return $?

termux_core__bash__termux_scoped_env_variable get-name "TERMUX_PREFIX__N" \
    ss="$TERMUX_ENV__SS_TERMUX" "PREFIX" || return $?


if [[ ! -x "$TERMUX_ROOTFS" ]] && [[ "$TUDO_SKIP_ON_NOOP_COMMAND" != "1" ]]; then
    tudo_log_errors "The TERMUX_ROOTFS '$TERMUX_ROOTFS' path not found or is not executable. Are you running in $TERMUX_APP__NAME app on Android?"
    return 1
fi

# Set variables to readonly to prevent modification by tudo.config
for var in TERMUX_ENV__SS_TERMUX TERMUX_ENV__S_TERMUX TERMUX_ROOTFS TERMUX_HOME TERMUX_PREFIX TERMUX_PREFIX__N; do
    readonly ${var}
done

}

##
# Function to set tudo default variables.
#
# `tudo_set_tudo_default_variables`
##
tudo_set_tudo_default_variables() {

### Set User Modifiable Variables Start
### It is highly advisable to use the tudo.config file instead to modify the default values

# Set TUDO_SHELL_HOME which will be used as tudo shell home directory
[ -n "$TUDO__SHELL_HOME" ] && CUSTOM_TUDO_SHELL_HOME_SET=1
TUDO_SHELL_HOME="${TUDO__SHELL_HOME:-$TERMUX_HOME}" # Default: `$TERMUX_HOME`

# Set TUDO_POST_SHELL_HOME which will be used as tudo post shell home directory
[ -n "$TUDO__POST_SHELL_HOME" ] && CUSTOM_TUDO_POST_SHELL_HOME_SET=1
TUDO_POST_SHELL_HOME="${TUDO__POST_SHELL_HOME:-$TERMUX_HOME}" # Default: `$TERMUX_HOME`

# Set the prompt string 1 for the tudo shell
TUDO_SHELL_PS1="${TUDO__SHELL_PS1:-Ⲧ }" # Default: `Ⲧ ` (U+2CA6, &#x2CA6;, coptic capital letter tau)

# Set the prompt string 1 for the tudo post shell
TUDO_POST_SHELL_PS1="${TUDO__POST_SHELL_PS1:-Ⲧ }" # Default: `Ⲧ ` (U+2CA6, &#x2CA6;, coptic capital letter tau)

# Set any additional paths you want to export other than termux bin, android bin and su bin paths,
# separated with colons `:`
# The string must not start or end with or contain two consecutive colons ':'
# The `--export-paths` option will override this value
TUDO_ADDITIONAL_PATHS_TO_EXPORT="${TUDO__ADDITIONAL_PATHS_TO_EXPORT:-}" # Default: ``

# Set to "1" or pass "-L" as argument if you want to automatically export all the paths that already exist
# in the PATH variable at the moment the tudo command is run
# The default paths mentioned above and any path in TUDO_ADDITIONAL_PATHS_TO_EXPORT are always exported
TUDO_EXPORT_ALL_EXISTING_PATHS_IN_PATH_VARIABLE="${TUDO__EXPORT_ALL_EXISTING_PATHS_IN_PATH_VARIABLE:-0}" # Default: `0`

# Set any additional ld library paths you want to export other than termux lib and android lib paths,
# separated with colons `:`
# The string must not start or end with or contain two consecutive colons ':'
# The `--export-ld-lib-paths` option will override this value
TUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT="${TUDO__ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT:-}" # Default: ``

# Set to "1" or pass "-P" as argument if you want to automatically export all the paths that already exist
# in the LD_LIBRARY_PATH variable at the moment the tudo command is run
# The default paths mentioned above and any path in TUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT are always exported
TUDO_EXPORT_ALL_EXISTING_PATHS_IN_LD_LIBRARY_PATH_VARIABLE="${TUDO__EXPORT_ALL_EXISTING_PATHS_IN_LD_LIBRARY_PATH_VARIABLE:-0}" # Default: `0`

# Set to 1 if you want to automatically create rc files for interactive shells, otherwise 0
TUDO_SHELLS_AUTOMATICALLY_CREATE_RC_FILES="${TUDO__SHELLS_AUTOMATICALLY_CREATE_RC_FILES:-1}" # Default: `1`

# Set to 1 if you want to automatically create history files for interactive shells, otherwise 0
TUDO_SHELLS_AUTOMATICALLY_CREATE_HISTORY_FILES="${TUDO__SHELLS_AUTOMATICALLY_CREATE_HISTORY_FILES:-1}" # Default: `1`

# Set to 1 if you want to store command history for interactive shells, otherwise 0
TUDO_SHELLS_HISTORY_ENABLED="${TUDO__SHELLS_HISTORY_ENABLED:-1}" # Default: `1`

# Set to "1" if you want to share rc files and history files between normal termux shell
# and tudo shell if TUDO_SHELL_HOME is same as TERMUX_HOME
TUDO_SHELL_SHARE_RCFILES_AND_HISTFILES="${TUDO__SHELL_SHARE_RCFILES_AND_HISTFILES:-1}" # Default: `1`

# Set to "1" if you want to share rc files and history files between normal termux shell
# and tudo post shell if TUDO_POST_SHELL_HOME is same as TERMUX_HOME
TUDO_POST_SHELL_SHARE_RCFILES_AND_HISTFILES="${TUDO__POST_SHELL_SHARE_RCFILES_AND_HISTFILES:-1}" # Default: `1`

# Set to 1 to add path to su binary directory to end of $PATH exported for android paths, otherwise 0.
# It is not added for `-A`, `-T` and `-TT` flags.
TUDO_ADD_SU_BIN_PATH_TO_PATH_VARIABLE="${TUDO__ADD_SU_BIN_PATH_TO_PATH_VARIABLE:-0}" # Default: `0`

# Set absolute path for su binary to use instead of searching for it in default search paths.
# This can be used if path is not in search paths or all paths in it should not be checked.
TUDO_SU_PATH="${TUDO__SU_PATH:-}" # Default: ``


# for f in TUDO_SHELL_HOME TUDO_POST_SHELL_HOME TUDO_SHELL_PS1 TUDO_POST_SHELL_PS1 TUDO_ADDITIONAL_PATHS_TO_EXPORT TUDO_EXPORT_ALL_EXISTING_PATHS_IN_PATH_VARIABLE TUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT TUDO_EXPORT_ALL_EXISTING_PATHS_IN_LD_LIBRARY_PATH_VARIABLE TUDO_SHELLS_AUTOMATICALLY_CREATE_RC_FILES TUDO_SHELLS_AUTOMATICALLY_CREATE_HISTORY_FILES TUDO_SHELLS_HISTORY_ENABLED TUDO_SHELL_SHARE_RCFILES_AND_HISTFILES TUDO_POST_SHELL_SHARE_RCFILES_AND_HISTFILES TUDO_ADD_SU_BIN_PATH_TO_PATH_VARIABLE TUDO_SU_PATH; do echo "$f=\`${!f}\`"; done; echo $'\n'

### Set User Modifiable Variables End


### Set Default Variables Start
# The following variables must not be modified unless you know what you are doing

TUDO_MAX_LOG_LEVEL=5 # Default: `5` (VVVERBOSE=5)
# shellcheck disable=SC2153
TUDO_LOG_LEVEL="$TUDO__LOG_LEVEL"
{ [[ ! "${TUDO_LOG_LEVEL:-}" =~ ^[0-9]+$ ]] || [[ "$TUDO_LOG_LEVEL" -gt "$TUDO_MAX_LOG_LEVEL" ]]; } && \
TUDO_LOG_LEVEL=1 # Default: `1` (OFF=0, NORMAL=1, DEBUG=2, VERBOSE=3, VVERBOSE=4 and VVVERBOSE=5)
TUDO_LOG_ARGS="${TUDO__LOG_ARGS:-0}" # Default: `0` (Export or manually set to `1` if you want to debug arguments received)

TUDO_NOOP_COMMAND=0 # Default: `0`
TUDO_DRY_RUN=0 # Default: `0`
COMMAND_TYPE="path" # Default: `path`
COMMAND_TYPE_PATH_FORCED=0 # Default: `0`
A_FLAG_PASSED=0 # Default: `0`
T_FLAG_PASSED=0 # Default: `0`

SAME_TUDO_POST_SHELL_AS_TUDO_SHELL=0 # Default: `0`
SAME_TUDO_POST_SHELL_HOME_AS_TUDO_SHELL_HOME=0 # Default: `0`
PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES=0 # Default: `0`
EXEC_TUDO_SHELL=0 # Default: `0`
DISABLE_STDIN_FOR_CORE_SCRIPT=0 # Default: `0`
RUN_CORE_SCRIPT_IN_BACKGROUND=0 # Default: `0`
EXIT_EARLY_IF_CORE_SCRIPT_FAILS=0 # Default: `0`
GO_BACK_TO_LAST_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT=0 # Default: `0`
GO_TO_LAUNCHER_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT=0 # Default: `0`
CLEAR_SHELL_AFTER_RUNNING_CORE_SCRIPT=0 # Default: `0`
RUN_INTERACTIVE_POST_TUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT=0 # Default: `0`
FORCE_USE_TEMP_SCRIPT_FILE_FOR_CORE_SCRIPT=0 # Default: `0`
CORE_SCRIPT_IS_PATH_TO_SCRIPT_FILE=0 # Default: `0`
DECODE_CORE_SCRIPT_CONTENT=0 # Default: `0`
DO_NOT_DELETE_TUDO_TEMP_DIRECTORY_ON_EXIT=0 # Default: `0`
REMOVE_PREVIOUS_TUDO_TEMP_FILES=0 # Default: `0`
HOLD_AFTER_TUDO=0 # Default: `0`
HOLD_ONLY_ON_FAILURE=0 # Default: `0`
SLEEP_AFTER_TUDO=0 # Default: `0`
SLEEP_ONLY_ON_FAILURE=0 # Default: `0`
DISABLE_ARGUMENTS_LOGGING=0 # Default: `0`
SET_TUDO_SHELL_TERMINAL_TITLE=0 # Default: `0`
PATH_PRIORITY="default" # Default: `default`
SET_SECONDARY_PRIORITY_PATHS=1 # Default: `1`
SET_SECONDARY_PATHS=1 # Default: `1`

TUDO_SHELL="" # Default: ``
TUDO_SHELL_BASENAME="" # Default: ``
TUDO_SHELL_PARENT_DIR="" # Default: ``
TUDO_POST_SHELL="" # Default: ``
TUDO_POST_SHELL_BASENAME="" # Default: ``
TUDO_POST_SHELL_PARENT_DIR="" # Default: ``
TUDO_SHELL_RCFILE="" # Default: ``
TUDO_POST_SHELL_RCFILE="" # Default: ``
TUDO_SHELL_HISTFILE="" # Default: ``
TUDO_POST_SHELL_HISTFILE="" # Default: ``
TUDO_TEMP_DIRECTORY="" # Default: ``
TUDO_TEMP_DIRECTORY_PREFIX=".tudo.temp" # Default: `.tudo.temp`
TUDO_CORE_SCRIPT_TEMP_FILENAME="" # Default: ``
TUDO_CORE_SCRIPT_REDIRECT_MODE="" # Default: ``
TUDO_SHELL_WORKING_DIR="" # Default: ``
TUDO_SHELL_TERMINAL_TITLE="" # Default: ``
ADDITIONAL_TUDO_SHELL_PRE_COMMANDS_TO_RUN="" # Default: ``
ADDITIONAL_TUDO_SHELL_POST_COMMANDS_TO_RUN="" # Default: ``
ADDITIONAL_TUDO_POST_SHELL_PRE_COMMANDS_TO_RUN="" # Default: ``
ADDITIONAL_TUDO_POST_SHELL_POST_COMMANDS_TO_RUN="" # Default: ``
TUDO_SHELL_STDIN_STRING="" # Default: ``
TUDO_POST_SHELL_STDIN_STRING="" # Default: ``
TUDO_SUPPORTED_SHELLS="" # Default: ``
TUDO_SUPPORTED_POST_SHELLS="" # Default: ``
SLEEP_TIME_AFTER_TUDO="" # Default: ``
HOLD_STRING_AFTER_TUDO="" # Default: ``
TUDO_XARGS_PATH="" # Default: ``
COMMA_ALTERNATIVE="‚"  # Default: `‚` (U+201A, &sbquo;, &#8218;, single low-9 quotation mark)
TUDO_ARG_MAX_SAFE_LIMIT=122880 # Default: `122880` (120KB, value should be in bytes)

TUDO_SUPPORTED_INTERACTIVE_SHELLS="bash zsh dash sh fish python ruby pry node perl lua5.2 lua5.3 lua5.4 php python2 ksh"
TUDO_SUPPORTED_SCRIPT_SHELLS="bash zsh dash sh fish python ruby node perl lua5.2 lua5.3 lua5.4 php python2 ksh"
TUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT="dash sh node php"

declare -ga TUDO_COMMAND=()
declare -ga SHELL_COMMAND=()
declare -ga SHELL_INTERACTIVE_COMMAND=()
declare -ga TUDO_SHELL_COMMAND=()
declare -ga TUDO_SHELL_INTERACTIVE_COMMAND=()
declare -ga TUDO_POST_SHELL_INTERACTIVE_COMMAND=()

declare -ga SHELL_ADDITIONAL_COMMAND_OPTIONS=()
declare -ga SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=()
declare -ga TUDO_SHELL_ADDITIONAL_COMMAND_OPTIONS=()
declare -ga TUDO_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=()
declare -ga TUDO_POST_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=()
declare -ga TUDO_RLWRAP_ADDITIONAL_COMMAND_OPTIONS=()

# Set regexes for validation
VALID_NUMBER_REGEX='^[0-9]+$'
VALID_ABSOLUTE_PATH_REGEX='^(/[^/]+)+$'
VALID_ROOTFS_OR_ABSOLUTE_PATH_REGEX='^((/)|((/[^/]+)+))$'
VALID_PATH_UNDER_TERMUX_ROOTFS_REGEX='^'"$TERMUX_ROOTFS"'/.+'
VALID_PATH_UNDER_TERMUX_HOME_REGEX='^'"$TERMUX_HOME"'/.+'

# Set termux and android env variables
TERMUX_BIN="$TERMUX_PREFIX/bin"
TERMUX_BIN_APPLETS="$TERMUX_PREFIX/bin/applets"
TERMUX_LD_LIBRARY_PATH="$TERMUX_PREFIX/lib"
TERMUX_LD_PRELOAD="$TERMUX_LD_LIBRARY_PATH/libtermux-exec.so"
TMPDIR="$TERMUX_PREFIX/tmp"

SYS_XBIN="/system/xbin"
SYS_BIN="/system/bin"
BASH_SHELL_PATH="$TERMUX_BIN/bash"
TERM="xterm-256color"

# Termux is currently an english-only environment
LANG="en_US.UTF-8"

### Set Default Variables End

}

function tudo_log() { local log_level="${1}"; shift; if [[ "$TUDO_LOG_LEVEL" -ge $log_level ]]; then echo "$@"; fi }
function tudo_log_literal() { local log_level="${1}"; shift; if [[ "$TUDO_LOG_LEVEL" -ge $log_level ]]; then echo -e "$@"; fi }
function tudo_log_errors() { echo "$@" 1>&2; }
function tudo_log_args() { if [[ $TUDO_LOG_ARGS == "1" ]]; then echo "$@"; fi }
function tudo_log_arg_errors() { echo "$@" 1>&2; }

# Enable the following line if you want to log function runtimes with the '-vv' option
#tudo_start_time=$(date +%s%3N); function tudo_log_literal() { local log_level="${1}"; shift; if [[ "$TUDO_LOG_LEVEL" -ge $log_level ]]; then if [[ "$*" == *"Running"* ]]; then tudo_end_time=$(date +%s%3N); run_time=$((tudo_end_time-tudo_start_time)); echo -e "Runtime $run_time\n"; tudo_start_time=$(date +%s%3N); fi; echo -e "$@"; fi }



##
# `tudo_main` [`<argument...>`]
##
tudo_main() {

    local return_value

    if [[ $# -eq 0 ]] || \
        [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]] || [[ "$1" == "--help-extra" ]] || \
        [[ "$1" == "--version" ]]; then
        TUDO_SKIP_ON_NOOP_COMMAND=1
    else
        TUDO_SKIP_ON_NOOP_COMMAND=0
    fi

    # Set termux env variables
    tudo_set_termux_env_variables || return $?

    # If `tudo.config` exists, source it.
    TUDO_CONFIG_FILE_PATH="$TERMUX_HOME/.config/tudo/tudo.config"
    TUDO_CONFIG_FILE_SOURCED=0
    if [[ "$TUDO_SKIP_ON_NOOP_COMMAND" != "1" ]] && \
        [ -f "$TUDO_CONFIG_FILE_PATH" ] && [ -r "$TUDO_CONFIG_FILE_PATH" ]; then
        # Set variables provided for `tudo.config`.
        TUDO__TERMUX_ROOTFS="$TERMUX_ROOTFS"
        TUDO__TERMUX_HOME="$TERMUX_HOME"
        TUDO__TERMUX_PREFIX="$TERMUX_PREFIX"

        # shellcheck source=tudo.config
        source "$TUDO_CONFIG_FILE_PATH" || return $?
        TUDO_CONFIG_FILE_SOURCED=1
    fi

    # Set tudo default variables.
    # They are set by a function so that default variables are not
    # overridden by the `tudo.config` file if its sourced.
    # However, the user modifiable variables will only be set if the
    # `tudo.config` didn't already set them or if they were not
    # already exported.
    tudo_set_tudo_default_variables || return $?


    # Set pre required variables to be used by this script
    if [[ "$TUDO_SKIP_ON_NOOP_COMMAND" != "1" ]]; then
        tudo_set_pre_required_variables || return $?
    fi


    # Process the command arguments passed to the script
    tudo_process_script_arguments "$@" || return $?

    [ "$TUDO_NOOP_COMMAND" = "1" ] && return 0

    # Validate COMMAND_TYPE
    if [ -z "$COMMAND_TYPE" ]; then
        tudo_show_help
        return_value=0
    elif [[ "$COMMAND_TYPE" != *,* ]] && [[ ",su,asu,path,script," == *",$COMMAND_TYPE,"* ]]; then
        tudo_run
        return_value=$?
    else
        tudo_log_errors "Unknown command type $COMMAND_TYPE"
        tudo_exit_on_args_error || return $?
    fi

    tudo_run_pre_exit_commands $return_value

    return $return_value

}

tudo_run() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo"

    # If `tudo.config` was sourced.
    if [[ "$TUDO_CONFIG_FILE_SOURCED" == "1" ]]; then
        tudo_log 3 "config was sourced from ~/.config/tudo/tudo.config"
    fi

    # If COMMAND_TYPE equals "su" or "asu"
    if [[ "$COMMAND_TYPE" == "su" ]] || [[ "$COMMAND_TYPE" == "asu" ]]; then
        TUDO_SUPPORTED_SHELLS="$TUDO_SUPPORTED_INTERACTIVE_SHELLS"

        # The arguments passed to '--shell-options' are meant for interactive shell
        TUDO_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=("${TUDO_SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
        TUDO_SHELL_ADDITIONAL_COMMAND_OPTIONS=()

        interactive_tudo_shell_required=1
    # If COMMAND_TYPE equals "path"
    elif [[ "$COMMAND_TYPE" == "path" ]]; then
        TUDO_SUPPORTED_SHELLS="bash"

        # Unset TUDO_SHELL so that it defaults to bash in tudo_set_tudo_shell
        TUDO_SHELL=""

        # Ignore any shell options that are passed
        TUDO_SHELL_ADDITIONAL_COMMAND_OPTIONS=()

        interactive_tudo_shell_required=0
    # If COMMAND_TYPE equals "script"
    elif [[ "$COMMAND_TYPE" == "script" ]]; then
        TUDO_SUPPORTED_SHELLS="$TUDO_SUPPORTED_SCRIPT_SHELLS"
        TUDO_SUPPORTED_POST_SHELLS="$TUDO_SUPPORTED_INTERACTIVE_SHELLS"

        interactive_tudo_shell_required=0
    else
        tudo_log_errors "COMMAND_TYPE '$COMMAND_TYPE' not handled while running tudo command in 'tudo_run'"
        return 1
    fi

    # If COMMAND_TYPE equals "script"
    if [[ "$COMMAND_TYPE" == "script" ]]; then
        # If DISABLE_STDIN_FOR_CORE_SCRIPT is enabled or stdin is not available while running this script,
        # then force enable DISABLE_STDIN_FOR_CORE_SCRIPT
        if [[ "$DISABLE_STDIN_FOR_CORE_SCRIPT" == "1" ]] || [ ! -t 0 ]; then
            DISABLE_STDIN_FOR_CORE_SCRIPT=1
        else
            DISABLE_STDIN_FOR_CORE_SCRIPT=0
        fi
    fi


    # If RUN_INTERACTIVE_POST_TUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT is enabled and COMMAND_TYPE equals "script"
    if [[ "$RUN_INTERACTIVE_POST_TUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT" == "1" ]] && [[ "$COMMAND_TYPE" == "script" ]]; then
        # If SAME_TUDO_POST_SHELL_HOME_AS_TUDO_SHELL_HOME is enabled
        if [[ "$SAME_TUDO_POST_SHELL_HOME_AS_TUDO_SHELL_HOME" == "1" ]]; then
            # Override TUDO_POST_SHELL_HOME
            TUDO_POST_SHELL_HOME="$TUDO_SHELL_HOME"
        fi
    else
        # Unset TUDO_POST_SHELL_HOME so that TUDO_POST_SHELL variables are not set
        TUDO_POST_SHELL_HOME=""
    fi


    # Test if bash shell executable file exists at BASH_SHELL_PATH
    # This is to ensure that bash shell is always the default shell if '--shell` and '--post-shell' options are not passed
    # and the shell is automatically validated so that it doesn't have to again in tudo_set_tudo_shell and tudo_set_tudo_post_shell
    # bash shell is also needed by the 'su --shell' command
    # tudo_run_file_type_tests_on_path label path log_file_tests_failure_errors show_stat_output_on_file_tests_failure check_if_absolute_path file_type_tests
    tudo_run_file_type_tests_on_path "BASH_SHELL_PATH" "$BASH_SHELL_PATH" 1 1 1 "frx" || return $?

    # If TUDO_ADD_SU_BIN_PATH_TO_PATH_VARIABLE is enabled
    if [[ "$TUDO_ADD_SU_BIN_PATH_TO_PATH_VARIABLE" == "1" ]]; then
        # Set SU and SU_BIN_PATH
        tudo_set_su_variables || return $?
    fi

    # Set required variables to be used by this script
    tudo_set_required_variables || return $?

    # Set priority_dependent_variables with termux priority
    tudo_set_priority_dependent_variables "termux" || return $?



    # Set TUDO_SHELL and TUDO_SHELL_BASENAME
    tudo_set_tudo_shell || return $?

    # If COMMAND_TYPE does not equal "path"
    # COMMAND_TYPE "path" does not use an interactive shell so no need to set these
    if [[ "$COMMAND_TYPE" != "path" ]]; then
        # Set TUDO_SHELL_RCFILE and TUDO_SHELL_RCFILE_VALUE to be sourced when TUDO_SHELL is run
        tudo_set_tudo_shell_rcfile || return $?

        # Set TUDO_SHELL_HISTFILE
        tudo_set_tudo_shell_histfile || return $?
    fi

    # Set TUDO_SHELL_COMMAND and TUDO_SHELL_INTERACTIVE_COMMAND command to be run
    tudo_set_tudo_shell_command || return $?



    # If TUDO_POST_SHELL_HOME is set
    if [ -n "$TUDO_POST_SHELL_HOME" ]; then
        # If SAME_TUDO_POST_SHELL_AS_TUDO_SHELL is enabled
        if [[ "$SAME_TUDO_POST_SHELL_AS_TUDO_SHELL" == "1" ]]; then
            # Override TUDO_POST_SHELL
            TUDO_POST_SHELL="$TUDO_SHELL"
        fi

        # Set TUDO_POST_SHELL and TUDO_POST_SHELL_BASENAME
        tudo_set_tudo_post_shell || return $?

        # Set TUDO_POST_SHELL_RCFILE and TUDO_POST_SHELL_RCFILE_VALUE to be sourced when TUDO_POST_SHELL is run
        tudo_set_tudo_post_shell_rcfile || return $?

        # Set TUDO_POST_SHELL_HISTFILE file
        tudo_set_tudo_post_shell_histfile || return $?

        # Set TUDO_POST_SHELL_INTERACTIVE_COMMAND command to be run
        tudo_set_tudo_post_shell_command || return $?
    fi



    # If COMMAND_TYPE equals "path"
    if [[ "$COMMAND_TYPE" == "path" ]]; then
        # Set TUDO_PATH_COMMAND
        tudo_set_tudo_command_path || return $?
    fi



    # Set PRE_TUDO_SHELL_COMMANDS_TO_RUN
    tudo_set_pre_tudo_shell_commands_to_run || return $?

    # If TUDO_POST_SHELL_HOME is set
    if [ -n "$TUDO_POST_SHELL_HOME" ]; then
        # Set PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN
        tudo_set_pre_tudo_post_shell_commands_to_run || return $?
    fi



    # Set traps to run commands before exiting tudo
    set_tudo_traps "tudo_trap" || return $?



    # If TUDO_DRY_RUN is not enabled
    if [[ "$TUDO_DRY_RUN" != "1" ]]; then
        # Create TUDO_SHELL_HOME, TUDO_SHELL_RCFILE, TUDO_SHELL_HISTFILE and/or
        # TUDO_POST_SHELL_HOME, TUDO_POST_SHELL_RCFILE, TUDO_POST_SHELL_HISTFILE
        # and TUDO_SHELL_WORKING_DIR if missing
        tudo_setup_tudo_shell_home_and_working_environment || return $?
    fi



    # Run tudo command depending on command type

    local TUDO_EXIT_CODE=0

    BASH_SHELL_COMMAND=("$BASH_SHELL_PATH" "--noprofile" "--norc")

    # If COMMAND_TYPE equals "su" or "asu"
    if [[ "$COMMAND_TYPE" == "su" ]] || [[ "$COMMAND_TYPE" == "asu" ]]; then

        # If TUDO_SHELL_INTERACTIVE_COMMAND is not set
        if [ ${#TUDO_SHELL_INTERACTIVE_COMMAND[@]} -eq 0 ]; then
            tudo_log_errors "TUDO_SHELL_INTERACTIVE_COMMAND is not set while running tudo $COMMAND_TYPE command in 'tudo_run'"
            return 1
        fi

        # If EXEC_TUDO_SHELL is enabled, then prepend "exec"
        if [[ "$EXEC_TUDO_SHELL" == "1" ]]; then
            BASH_SHELL_COMMAND=("exec" "${BASH_SHELL_COMMAND[@]}")
        fi

        # Set TUDO_COMMAND_TO_RUN to run PRE_TUDO_SHELL_COMMANDS_TO_RUN and then
        # start an interactive TUDO_SHELL
        TUDO_COMMAND_TO_RUN="$PRE_TUDO_SHELL_COMMANDS_TO_RUN"
        printf -v "TUDO_SHELL_INTERACTIVE_COMMAND_STRING" "$TUDO_SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT" "${TUDO_SHELL_INTERACTIVE_COMMAND[@]}"
        TUDO_COMMAND_TO_RUN+="$TUDO_SHELL_INTERACTIVE_COMMAND_STRING"

        # If TUDO_SHELL_STDIN_STRING is set
        if [ -n "$TUDO_SHELL_STDIN_STRING" ]; then
            # If TUDO_SHELL_BASENAME is in TUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT
            if [[ " $TUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT " == *" $TUDO_SHELL_BASENAME "* ]]; then
                # Pass TUDO_SHELL_STDIN_STRING as stdin with a herestring to TUDO_SHELL
                TUDO_COMMAND_TO_RUN+=' <<<'"'${TUDO_SHELL_STDIN_STRING//\'/\'\\\'\'}'"
            else
                # Pass TUDO_SHELL_STDIN_STRING as stdin with process substitution to TUDO_SHELL
                TUDO_COMMAND_TO_RUN+=' < <(printf "%s" '"'${TUDO_SHELL_STDIN_STRING//\'/\'\\\'\'}'"')'
            fi
        fi


        tudo_log_literal 3 "\n\n\nRunning tudo $COMMAND_TYPE commmand"
        tudo_log 2 $'\n'"BASH_SHELL_COMMAND=\`${BASH_SHELL_COMMAND[*]}\`"
        tudo_log 2 $'\n'"TUDO_COMMAND_TO_RUN=\`$TUDO_COMMAND_TO_RUN\`"

        # If TUDO_DRY_RUN is not enabled
        if [[ "$TUDO_DRY_RUN" != "1" ]]; then
            # Run TUDO_COMMAND_TO_RUN
            "${BASH_SHELL_COMMAND[@]}" <(printf "%s" "$TUDO_COMMAND_TO_RUN")
            TUDO_EXIT_CODE=$?
        fi


    # If COMMAND_TYPE equals "path"
    elif [[ "$COMMAND_TYPE" == "path" ]]; then

        # Set script to run in TUDO_PATH_COMMAND_TO_RUN
        tudo_set_tudo_path_command || return $?

        # If EXEC_TUDO_SHELL is enabled, then prepend "exec"
        if [[ "$EXEC_TUDO_SHELL" == "1" ]]; then
            BASH_SHELL_COMMAND=("exec" "${BASH_SHELL_COMMAND[@]}")
        fi

        # Set TUDO_COMMAND_TO_RUN to run PRE_TUDO_SHELL_COMMANDS_TO_RUN and then
        # run the TUDO_PATH_COMMAND_TO_RUN
        TUDO_COMMAND_TO_RUN="$PRE_TUDO_SHELL_COMMANDS_TO_RUN$TUDO_PATH_COMMAND_TO_RUN"


        tudo_log_literal 3 "\n\n\nRunning tudo $COMMAND_TYPE commmand"
        tudo_log 2 $'\n'"BASH_SHELL_COMMAND=\`${BASH_SHELL_COMMAND[*]}\`"

        # If DISABLE_ARGUMENTS_LOGGING is not enabled
        if [[ "$DISABLE_ARGUMENTS_LOGGING" != "1" ]]; then
            tudo_log 2 $'\n'"TUDO_COMMAND_TO_RUN=\`$TUDO_COMMAND_TO_RUN\`"
        fi

        # If TUDO_DRY_RUN is not enabled
        if [[ "$TUDO_DRY_RUN" != "1" ]]; then
            # Run TUDO_COMMAND_TO_RUN
            "${BASH_SHELL_COMMAND[@]}" <(printf "%s" "$TUDO_COMMAND_TO_RUN")
            TUDO_EXIT_CODE=$?
        fi


    # If COMMAND_TYPE equals "script"
    elif [[ "$COMMAND_TYPE" == "script" ]]; then

        # If TUDO_SHELL_COMMAND is not set
        if [ ${#TUDO_SHELL_COMMAND[@]} -eq 0 ]; then
            tudo_log_errors "TUDO_SHELL_COMMAND is not set while running tudo $COMMAND_TYPE command in 'tudo_run'"
            return 1
        fi

        # If RUN_INTERACTIVE_POST_TUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT is enabled and TUDO_POST_SHELL_INTERACTIVE_COMMAND is not set
        if [[ "$RUN_INTERACTIVE_POST_TUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT" == "1" ]] && [ ${#TUDO_POST_SHELL_INTERACTIVE_COMMAND[@]} -eq 0 ]; then
            tudo_log_errors "TUDO_POST_SHELL_INTERACTIVE_COMMAND is not set while running tudo $COMMAND_TYPE command in 'tudo_run'"
            return 1
        fi

        # Set script to run in TUDO_SCRIPT_COMMAND_TO_RUN
        tudo_set_tudo_script_command || return $?

        # If EXEC_TUDO_SHELL is enabled, then prepend "exec"
        if [[ "$EXEC_TUDO_SHELL" == "1" ]]; then
            BASH_SHELL_COMMAND=("exec" "${BASH_SHELL_COMMAND[@]}")
        fi

        # Set TUDO_COMMAND_TO_RUN to run TUDO_SCRIPT_COMMAND_TO_RUN
        TUDO_COMMAND_TO_RUN="$TUDO_SCRIPT_COMMAND_TO_RUN"


        tudo_log_literal 3 "\n\n\nRunning tudo $COMMAND_TYPE commmand"
        tudo_log 2 $'\n'"BASH_SHELL_COMMAND=\`${BASH_SHELL_COMMAND[*]}\`"

        # If DISABLE_ARGUMENTS_LOGGING is not enabled
        if [[ "$DISABLE_ARGUMENTS_LOGGING" != "1" ]]; then
            tudo_log 2 $'\n'"TUDO_COMMAND_TO_RUN=\`$TUDO_COMMAND_TO_RUN\`"
        fi

        # If TUDO_DRY_RUN is not enabled
        if [[ "$TUDO_DRY_RUN" != "1" ]]; then
            # Run TUDO_COMMAND_TO_RUN
            "${BASH_SHELL_COMMAND[@]}" <(printf "%s" "$TUDO_COMMAND_TO_RUN")
            TUDO_EXIT_CODE=$?
        fi


    else
        tudo_log_errors "COMMAND_TYPE '$COMMAND_TYPE' not handled while running tudo command in 'tudo_run'"
        return 1
    fi

    # If TUDO_DRY_RUN is not enabled
    if [[ "$TUDO_DRY_RUN" != "1" ]]; then
        tudo_log 3 $'\n'"TUDO_EXIT_CODE='$TUDO_EXIT_CODE'"
    fi

    # If tudo is being run in an interactive shell, then reset terminal
    if [[ $- == *i* ]]; then
        stty sane &>/dev/null
    fi

    return $TUDO_EXIT_CODE

}

##
# `tudo_run_pre_exit_commands` `<exit_code>`
##
tudo_run_pre_exit_commands() {

    local return_value

    local exit_code="$1"

    # If HOLD_AFTER_TUDO is enabled
    if [[ "$HOLD_AFTER_TUDO" == "1" ]]; then
        # If HOLD_ONLY_ON_FAILURE is not enabled or (HOLD_ONLY_ON_FAILURE is enabled and exit_code does not equal 0)
        if [[ "$HOLD_ONLY_ON_FAILURE" != "1" ]] || { [[ "$HOLD_ONLY_ON_FAILURE" == "1" ]] && [[ "$exit_code" != "0" ]]; }; then
            # If stdin and stdout are available
            if [ -t 0 ] && [ -t 1 ]; then
                # If HOLD_STRING_AFTER_TUDO is set
                if [ -n "$HOLD_STRING_AFTER_TUDO" ]; then
                    local valid_alphanumeric_and_punct_string_regex='^[[:alnum:][:punct:]]+$'

                    if [[ "$HOLD_STRING_AFTER_TUDO" =~ $valid_alphanumeric_and_punct_string_regex ]]; then
                        # Read from stdin until HOLD_STRING_AFTER_TUDO is correctly entered
                        # read should never timeout because of TMOUT=0
                        local exit_while=0
                        while [[ $exit_while != "1" ]]; do
                            TMOUT=0 read -p "Enter '$HOLD_STRING_AFTER_TUDO' to exit:"$'\n' input
                            if [ $? -ne 0 ] || [[ "$input" == "$HOLD_STRING_AFTER_TUDO" ]]; then
                                exit_while=1
                            fi
                        done
                    else
                        tudo_log_errors "HOLD_STRING_AFTER_TUDO '$HOLD_STRING_AFTER_TUDO' is invalid. It can only contain alphanumeric and punctuation characters"
                        return 1
                    fi

                # Else if only '--hold' was passed
                else
                    # Read any character from stdin in silent mode
                    # read should never timeout because of TMOUT=0
                    TMOUT=0 read -s -n 1
                fi
            fi
        fi
    fi

    # If SLEEP_AFTER_TUDO is enabled
    if [[ "$SLEEP_AFTER_TUDO" == "1" ]]; then
        # If SLEEP_ONLY_ON_FAILURE is not enabled or (SLEEP_ONLY_ON_FAILURE is enabled and exit_code does not equal 0)
        if [[ "$SLEEP_ONLY_ON_FAILURE" != "1" ]] || { [[ "$SLEEP_ONLY_ON_FAILURE" == "1" ]] && [[ "$exit_code" != "0" ]]; }; then
            local valid_floating_point_number_regex='^[0-9]+(\.[0-9]+)?$'

            if [[ "$SLEEP_TIME_AFTER_TUDO" =~ $valid_floating_point_number_regex ]]; then
                # Sleep for SLEEP_TIME_AFTER_TUDO seconds
                sleep "$SLEEP_TIME_AFTER_TUDO"
            else
                tudo_log_errors "SLEEP_TIME_AFTER_TUDO '$SLEEP_TIME_AFTER_TUDO' is not a valid floating point number"
                return 1
            fi
        fi
    fi

    return 0

}

tudo_set_su_variables() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_set_su_variables"

    SU=""
    SU_BIN_PATH=""
  
    local -a su_search_paths=()

    # Check "`su` search paths" in README for more info.
    # If TUDO_SU_PATH is not a valid absolute path
    if [[ ! "$TUDO_SU_PATH" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        su_search_paths+=("/system/bin/su" "/debug_ramdisk/su" "/system/xbin/su" "/sbin/su" "/sbin/bin/su" "/system/sbin/su" "/su/xbin/su" "/su/bin/su" "/magisk/.core/bin/su")
    else
        su_search_paths+=("$TUDO_SU_PATH")
    fi

    local su
    local su_found=0
    local su_help=""

    for su in "${su_search_paths[@]}"; do
        if [ -x "$su" ]; then
            tudo_log 3 "A su binary found at '$su'"
            su_found=1

            # If '-c' option is not supported, then continue searching
            if [[ "$su_help" != *"-c,"* ]] && [[ "$su_help" != *"-c "* ]]; then
                tudo_log 3 "The su binary found does not support '-c' option, continuing search"
                continue
            # If '--shell' option is not supported, then continue searching
            elif [[ "$su_help" != *"--shell"* ]]; then
                tudo_log 3 "The su binary found does not support '--shell' option, continuing search"
                continue
            # If '--preserve-environment' option is not supported, then continue searching
            elif [[ "$su_help" != *"--preserve-environment"* ]]; then
                tudo_log 3 "The su binary found does not support '--preserve-environment' option, continuing search"
                continue
            # If '--mount-master' option is not supported, then continue searching
            elif [[ "$su_help" != *"--mount-master"* ]]; then
                tudo_log 3 "The su binary found does not support '--mount-master' option, continuing search"
                continue
            # Else use the su
            else
                SU="$su"

                SU_BIN_PATH_BASENAME="${SU##*/}" # Strip longest match of */ from start
                SU_BIN_PATH="${SU:0:${#SU} - ${#SU_BIN_PATH_BASENAME}}" # Substring from 0 to position of basename
                case "$SU_BIN_PATH" in *[!/]*/) SU_BIN_PATH="${SU_BIN_PATH%"${SU_BIN_PATH##*[!/]}"}";; *[/]) SU_BIN_PATH="/";; esac # Remove trailing slashes if not root

                break
            fi

            tudo_log 3 ""
        fi
    done

    # If SU is not set
    if [ -z "$SU" ]; then
         # If su_found is not set to "1"
        if [[ "$su_found" != "1" ]]; then
            tudo_log 3 "No 'su' binary found"
        else
            tudo_log 3 "No 'su' binary found that supports the '-c', '--shell', '--preserve-environment' and '--mount-master' options"
        fi

        tudo_log 3 "SU_SEARCH_PATHS: ${su_search_paths[*]}"
    else
        tudo_log 3 "SU='$SU'"
        tudo_log 3 "SU_BIN_PATH='$SU_BIN_PATH'"
    fi

    return 0

}

tudo_set_pre_required_variables() {

    local return_value

    # Find android sdk/os version
    # Termux app exports ANDROID__BUILD_VERSION_SDK for `>= v0.119.0`
    if [[ ! "$ANDROID__BUILD_VERSION_SDK" =~ $VALID_NUMBER_REGEX ]]; then
        ANDROID__BUILD_VERSION_SDK="$(unset LD_LIBRARY_PATH; unset LD_PRELOAD; getprop "ro.build.version.sdk")"
        return_value=$?
        if [ $return_value -ne 0 ] || [[ ! "$ANDROID__BUILD_VERSION_SDK" =~ $VALID_NUMBER_REGEX ]]; then
            tudo_log_errors "Failure while finding 'ro.build.version.sdk' property"
            tudo_log_errors "ANDROID__BUILD_VERSION_SDK='$ANDROID__BUILD_VERSION_SDK'"
            if [ $return_value -eq 0 ]; then
                return_value=1
            fi
            return $return_value
        fi
    fi

    tudo_log 3 "ANDROID__BUILD_VERSION_SDK='$ANDROID__BUILD_VERSION_SDK'"



    # Set LD_LIBRARY_PATH for all external commands that may be run
    # If on Android `< 7`
    if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ]; then
        # Set only termux library paths
        LD_LIBRARY_PATH="$TERMUX_LD_LIBRARY_PATH"
    else
        # Do not set termux or android library paths
        LD_LIBRARY_PATH=""
    fi

    tudo_log 3 "LD_LIBRARY_PATH='$LD_LIBRARY_PATH'"

    return 0

}

tudo_set_required_variables() {

    local return_value

    # Do not modify unless you known what you are doing

    tudo_log_literal 3 "\nRunning tudo_set_required_variables"

    # Set LD_PRELOAD
    export LD_PRELOAD="$TERMUX_LD_PRELOAD"

    local remove_duplicates_in_path_variable=0
    local remove_duplicates_in_ld_library_path_variable=0

    # Store PATH and LD_LIBRARY_PATH
    OLD_PATH="$PATH"
    OLD_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"


    # Set PATH
    PATH="$TERMUX_BIN:$TERMUX_BIN_APPLETS:$SYS_XBIN:$SYS_BIN"

    tudo_log 3 "PATH='$PATH'"


    # Set current working directory
    CURRENT_WORKING_DIR="$PWD"
    # Do not needlessly create a subshell
    if [[ ! "$CURRENT_WORKING_DIR" =~ $VALID_ROOTFS_OR_ABSOLUTE_PATH_REGEX ]]; then
        # We use `-L` logical mode as its default bash shell behaviour for `pwd` builtin,
        # unlike `pwd` external command, which uses `-P` physical mode by default.
        # - https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html#index-pwd
        # - https://github.com/bminor/bash/blob/bash-5.2/builtins/cd.def#L472
        # - https://man7.org/linux/man-pages/man1/pwd.1.html
        CURRENT_WORKING_DIR="$(pwd -L)"
        return_value=$?
        if [ $return_value -ne 0 ] || [[ ! "$CURRENT_WORKING_DIR" =~ $VALID_ROOTFS_OR_ABSOLUTE_PATH_REGEX ]]; then
            tudo_log_errors "Failure while finding current working directory"
            tudo_log_errors "CURRENT_WORKING_DIR='$CURRENT_WORKING_DIR'"
            if [ $return_value -eq 0 ]; then
                return_value=1
            fi
            return $return_value
        fi
    fi

    tudo_log 3 "CURRENT_WORKING_DIR='$CURRENT_WORKING_DIR'"



    # Set path priority variables to use depending on android or termux priority
    tudo_set_path_priority_variables "$SET_SECONDARY_PATHS"



    # Set variables for PATH_TO_EXPORT
    if [[ "$SET_SECONDARY_PRIORITY_PATHS" == "1" ]]; then
        # Set termux followed by android paths to give termux paths priority for `-t` flag
        TERMUX_PRIORITY_PATH="$TERMUX_PATH:$ANDROID_PATH"

        # Set android followed by termux paths to give android paths priority for `-a` flag
        ANDROID_PRIORITY_PATH="$ANDROID_PATH:$TERMUX_PATH"
    else
        # Set only termux paths for `-T` and `-TT` flag
        # No need to add SU_BIN_PATH as termux su wrapper in TERMUX_BIN would override it
        TERMUX_PRIORITY_PATH="$TERMUX_PATH"

        # Set only android paths for `-A` and `-AA` flag
        ANDROID_PRIORITY_PATH="$ANDROID_PATH"
    fi


    # If TUDO_EXPORT_ALL_EXISTING_PATHS_IN_PATH_VARIABLE is enabled and OLD_PATH is not empty, then append it to PATH variables
    if [[ "$TUDO_EXPORT_ALL_EXISTING_PATHS_IN_PATH_VARIABLE" == "1" ]] && [ -n "$OLD_PATH" ]; then
        TERMUX_PRIORITY_PATH+=":$OLD_PATH"
        ANDROID_PRIORITY_PATH+=":$OLD_PATH"
        remove_duplicates_in_path_variable=1
    fi

    # If TUDO_ADDITIONAL_PATHS_TO_EXPORT is not empty, then append it to PATH variables
    if [ -n "$TUDO_ADDITIONAL_PATHS_TO_EXPORT" ]; then
        TERMUX_PRIORITY_PATH+=":$TUDO_ADDITIONAL_PATHS_TO_EXPORT"
        ANDROID_PRIORITY_PATH+=":$TUDO_ADDITIONAL_PATHS_TO_EXPORT"
        remove_duplicates_in_path_variable=1
    fi


    # Remove_duplicates_in_path_variable is only enabled if custom paths are added to the PATH variables
    # This will reduce execution time since an external call to awk with a subshell will be made
    # Default paths set must not have any duplicates

    # Remove duplicates from TERMUX_PRIORITY_PATH and check if it is valid and can be used as the PATH variable
    tudo_parse_and_validate_path_variable "TERMUX_PRIORITY_PATH" "TERMUX_PRIORITY_PATH" "$TERMUX_PRIORITY_PATH" "$remove_duplicates_in_path_variable"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failed to parse and validate 'TERMUX_PRIORITY_PATH'"
        return $return_value
    fi

    # Remove duplicates from ANDROID_PRIORITY_PATH and check if it is valid and can be used as the PATH variable
    tudo_parse_and_validate_path_variable "ANDROID_PRIORITY_PATH" "ANDROID_PRIORITY_PATH" "$ANDROID_PRIORITY_PATH" "$remove_duplicates_in_path_variable"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failed to parse and validate 'ANDROID_PRIORITY_PATH'"
        return $return_value
    fi



    # If on Android `< 7`
    if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ]; then
        # Set only termux library path for all `-t`, `-T` and `-TT` flags
        TERMUX_PRIORITY_LD_LIBRARY_PATH="$TERMUX_LD_LIBRARY_PATH"

        # Set only termux library path for `-a` flag but not for `-A` and `-AA` flags
        if [[ "$SET_SECONDARY_PRIORITY_PATHS" == "1" ]]; then
            ANDROID_PRIORITY_LD_LIBRARY_PATH="$TERMUX_LD_LIBRARY_PATH"
        else
            ANDROID_PRIORITY_LD_LIBRARY_PATH=""
        fi
    else
        # Do not set termux or android library paths for any flags
        TERMUX_PRIORITY_LD_LIBRARY_PATH=""
        ANDROID_PRIORITY_LD_LIBRARY_PATH=""
    fi


    # If TUDO_EXPORT_ALL_EXISTING_PATHS_IN_LD_LIBRARY_PATH_VARIABLE is enabled and OLD_LD_LIBRARY_PATH is not empty, then append it to LD_LIBRARY_PATH variables
    if [[ "$TUDO_EXPORT_ALL_EXISTING_PATHS_IN_LD_LIBRARY_PATH_VARIABLE" == "1" ]] && [ -n "$OLD_LD_LIBRARY_PATH" ]; then
        TERMUX_PRIORITY_LD_LIBRARY_PATH+=":$OLD_LD_LIBRARY_PATH"
        ANDROID_PRIORITY_LD_LIBRARY_PATH+=":$OLD_LD_LIBRARY_PATH"
        remove_duplicates_in_ld_library_path_variable=1
    fi

    # If TUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT is not empty, then append it to LD_LIBRARY_PATH variables
    if [ -n "$TUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT" ]; then
        TERMUX_PRIORITY_LD_LIBRARY_PATH+=":$TUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT"
        ANDROID_PRIORITY_LD_LIBRARY_PATH+=":$TUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT"
        remove_duplicates_in_ld_library_path_variable=1
    fi


    # Remove_duplicates_in_path_variable is only enabled if custom paths are added to the LD_LIBRARY_PATH variables
    # This will reduce execution time since an external call to awk with a subshell will be made
    # Default paths set must not have any duplicates

    # Remove duplicates from TERMUX_PRIORITY_LD_LIBRARY_PATH and check if it is valid and can be used as the LD_LIBRARY_PATH variable
    tudo_parse_and_validate_path_variable "TERMUX_PRIORITY_LD_LIBRARY_PATH" "TERMUX_PRIORITY_LD_LIBRARY_PATH" "$TERMUX_PRIORITY_LD_LIBRARY_PATH" "$remove_duplicates_in_ld_library_path_variable"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failed to parse and validate 'TERMUX_PRIORITY_LD_LIBRARY_PATH'"
        return $return_value
    fi

    # Remove duplicates from ANDROID_PRIORITY_LD_LIBRARY_PATH and check if it is valid and can be used as the LD_LIBRARY_PATH variable
    tudo_parse_and_validate_path_variable "ANDROID_PRIORITY_LD_LIBRARY_PATH" "ANDROID_PRIORITY_LD_LIBRARY_PATH" "$ANDROID_PRIORITY_LD_LIBRARY_PATH" "$remove_duplicates_in_ld_library_path_variable"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failed to parse and validate 'ANDROID_PRIORITY_LD_LIBRARY_PATH'"
        return $return_value
    fi



    # Set TERMUX_PRIORITY_LD_PRELOAD_COMMAND to set LD_PRELOAD to libtermux-exec.so
    TERMUX_PRIORITY_LD_PRELOAD_COMMAND="export LD_PRELOAD='${LD_PRELOAD//\'/\'\\\'\'}';"

    # Set ANDROID_PRIORITY_LD_PRELOAD_COMMAND to unset LD_PRELOAD
    ANDROID_PRIORITY_LD_PRELOAD_COMMAND="unset LD_PRELOAD;"



    # Set TUDO_SHELL_HOME
    tudo_trim_trailing_newlines "TUDO_SHELL_HOME" "$TUDO_SHELL_HOME"

    # Replace "$PREFIX/" or "~/" prefix with termux absolute paths in TUDO_SHELL_HOME
    # Canonicalize_path is only enabled if a custom path was passed for TUDO_SHELL_HOME by the user
    # This will reduce execution time since an external call to readlink with a subshell will be made
    tudo_expand_termux_path "TUDO_SHELL_HOME" "TUDO_SHELL_HOME" "$TUDO_SHELL_HOME" "$TERMUX_PREFIX" "$TERMUX_HOME" "$CUSTOM_TUDO_SHELL_HOME_SET"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failed to expand TUDO_SHELL_HOME '$TUDO_SHELL_HOME'"
        return $return_value
    fi

    # If TUDO_SHELL_HOME is not a valid absolute path
    if [[ ! "$TUDO_SHELL_HOME" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        tudo_log_errors "The TUDO_SHELL_HOME '$TUDO_SHELL_HOME' is not a valid absolute path"
        return 1
    fi

    # If TUDO_SHELL_HOME is not set to an absolute path under TERMUX_ROOTFS
    if [[ ! "$TUDO_SHELL_HOME" =~ $VALID_PATH_UNDER_TERMUX_ROOTFS_REGEX ]]; then
        tudo_log_errors "The TUDO_SHELL_HOME '$TUDO_SHELL_HOME' must be an absolute path under TERMUX_ROOTFS '$TERMUX_ROOTFS'"
    fi

    tudo_log 3 "TUDO_SHELL_HOME='$TUDO_SHELL_HOME'"

    # Find the parent directory of the TUDO_SHELL_HOME
    TUDO_SHELL_HOME_BASENAME="${TUDO_SHELL_HOME##*/}" # Strip longest match of */ from start
    TUDO_SHELL_HOME_PARENT_DIR="${TUDO_SHELL_HOME:0:${#TUDO_SHELL_HOME} - ${#TUDO_SHELL_HOME_BASENAME}}" # Substring from 0 to position of basename
    case "$TUDO_SHELL_HOME_PARENT_DIR" in *[!/]*/) TUDO_SHELL_HOME_PARENT_DIR="${TUDO_SHELL_HOME_PARENT_DIR%"${TUDO_SHELL_HOME_PARENT_DIR##*[!/]}"}";; *[/]) TUDO_SHELL_HOME_PARENT_DIR="/";; esac # Remove trailing slashes if not root

    tudo_log 3 "TUDO_SHELL_HOME_PARENT_DIR='$TUDO_SHELL_HOME_PARENT_DIR'"


    # If TUDO_POST_SHELL_HOME is set
    if [ -n "$TUDO_POST_SHELL_HOME" ]; then
        # Set TUDO_POST_SHELL_HOME
        tudo_trim_trailing_newlines "TUDO_POST_SHELL_HOME" "$TUDO_POST_SHELL_HOME"

        # Replace "$PREFIX/" or "~/" prefix with termux absolute paths in TUDO_POST_SHELL_HOME
        # Canonicalize_path is only enabled if a custom path was passed for TUDO_POST_SHELL_HOME by the user
        # This will reduce execution time since an external call to readlink with a subshell will be made
        tudo_expand_termux_path "TUDO_POST_SHELL_HOME" "TUDO_POST_SHELL_HOME" "$TUDO_POST_SHELL_HOME" "$TERMUX_PREFIX" "$TERMUX_HOME" "$CUSTOM_TUDO_POST_SHELL_HOME_SET"
        return_value=$?
        if [ $return_value -ne 0 ]; then
            tudo_log_errors "Failed to expand 'TUDO_POST_SHELL_HOME'"
            return $return_value
        fi

        # If TUDO_POST_SHELL_HOME is not a valid absolute path
        if [[ ! "$TUDO_POST_SHELL_HOME" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
            tudo_log_errors "The TUDO_POST_SHELL_HOME '$TUDO_POST_SHELL_HOME' is not a valid absolute path"
            return 1
        fi

        # If TUDO_POST_SHELL_HOME is not set to an absolute path under TERMUX_ROOTFS
        if [[ ! "$TUDO_POST_SHELL_HOME" =~ $VALID_PATH_UNDER_TERMUX_ROOTFS_REGEX ]]; then
            tudo_log_errors "The TUDO_POST_SHELL_HOME '$TUDO_POST_SHELL_HOME' must be an absolute path under TERMUX_ROOTFS '$TERMUX_ROOTFS'"
        fi

        tudo_log 3 "TUDO_POST_SHELL_HOME='$TUDO_POST_SHELL_HOME'"

        # Find the parent directory of the TUDO_POST_SHELL_HOME
        TUDO_POST_SHELL_HOME_BASENAME="${TUDO_POST_SHELL_HOME##*/}" # Strip longest match of */ from start
        TUDO_POST_SHELL_HOME_PARENT_DIR="${TUDO_POST_SHELL_HOME:0:${#TUDO_POST_SHELL_HOME} - ${#TUDO_POST_SHELL_HOME_BASENAME}}" # Substring from 0 to position of basename
        case "$TUDO_POST_SHELL_HOME_PARENT_DIR" in *[!/]*/) TUDO_POST_SHELL_HOME_PARENT_DIR="${TUDO_POST_SHELL_HOME_PARENT_DIR%"${TUDO_POST_SHELL_HOME_PARENT_DIR##*[!/]}"}";; *[/]) TUDO_POST_SHELL_HOME_PARENT_DIR="/";; esac # Remove trailing slashes if not root

        tudo_log 3 "TUDO_POST_SHELL_HOME_PARENT_DIR='$TUDO_POST_SHELL_HOME_PARENT_DIR'"
    fi


    # Set TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY
    tudo_set_tudo_temp_directory_parent_directory || return $?

    # If TUDO_SHELL_WORKING_DIR is set
    if [ -n "$TUDO_SHELL_WORKING_DIR" ]; then
        # Set TUDO_SHELL_WORKING_DIR
        tudo_set_tudo_shell_working_dir || return $?
    fi



    # Create TMPDIR if missing
    tudo_setup_termux_tmp_dir || return $?


    return 0

}

##
# Set termux and android path priority variables that should be used
# depending on required priority.
#
#
# `tudo_set_path_priority_variables` `<set_secondary_paths>`
tudo_set_path_priority_variables() {

    local set_secondary_paths="$1"

    # Set TERMUX_PATH
    if [[ "$set_secondary_paths" == "1" ]]; then
        TERMUX_PATH="$TERMUX_BIN:$TERMUX_BIN_APPLETS"
    else
        TERMUX_PATH="$TERMUX_BIN"
    fi


    # Set ANDROID_PATH
    if [[ "$set_secondary_paths" == "1" ]]; then
        # If android >= 11
        if [ "$ANDROID__BUILD_VERSION_SDK" -ge 30 ]; then
            # - https://cs.android.com/android/platform/superproject/+/android-11.0.0_r1:bionic/libc/include/paths.h;l=50
            # - https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:bionic/libc/include/paths.h;l=50
            ANDROID_PATH="/product/bin:/apex/com.android.runtime/bin:/apex/com.android.art/bin:/system_ext/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin"
        # If android >= 10
        elif [ "$ANDROID__BUILD_VERSION_SDK" -ge 29 ]; then
            # - https://cs.android.com/android/platform/superproject/+/android-10.0.0_r1:bionic/libc/include/paths.h;l=50
            ANDROID_PATH="/sbin:/system/sbin:/product/bin:/apex/com.android.runtime/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin"
        # If android >= 9
        elif [ "$ANDROID__BUILD_VERSION_SDK" -ge 28 ]; then
            # - https://cs.android.com/android/platform/superproject/+/android-9.0.0_r1:bionic/libc/include/paths.h;l=41
            ANDROID_PATH="/sbin:/system/sbin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin"
        # If android >= 8
        elif [ "$ANDROID__BUILD_VERSION_SDK" -ge 26 ]; then
            # - https://cs.android.com/android/platform/superproject/+/android-8.0.0_r1:bionic/libc/include/paths.h;l=39
            ANDROID_PATH="/sbin:/system/sbin:/system/bin:/system/xbin:/vendor/bin:/vendor/xbin"
        # If android < 8   
        # - https://cs.android.com/android/platform/superproject/+/android-7.0.0_r1:bionic/libc/include/paths.h;l=37    
        else
            ANDROID_PATH="/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin"
        fi

        # If SU_BIN_PATH is not empty and if it does not already exist in ANDROID_PATH, then append it to ANDROID_PATH
        if [ -n "$SU_BIN_PATH" ] && [[ "$SU_BIN_PATH" != *:* ]] && [[ ":$ANDROID_PATH:" != *":$SU_BIN_PATH:"* ]]; then
            ANDROID_PATH+=":$SU_BIN_PATH"
        fi
    else
        ANDROID_PATH="$SYS_BIN"
    fi

    return 0

}

##
# Set variables to export with priority to termux or android bin and library paths.
#
# `priority` must be one of `termux` or `android`.
#
# `tudo_set_priority_dependent_variables` `<priority>`
##
tudo_set_priority_dependent_variables() {

    local return_value

    # If argument count is not 1
    if [ $# -ne 1 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_set_priority_dependent_variables'"
        return 1
    fi

    local priority="$1"

    if [[ "$priority" != "termux" ]] && [[ "$priority" != "android" ]]; then
        tudo_log_errors "priority '$priority' passed to 'tudo_set_priority_dependent_variables' does not equal 'termux' or 'android'"
        return 1
    fi

    # If priority to the previous call to this function was the same, then just return
    if [[ "$priority" == "$previous_priority_dependent_variables_priortiy" ]]; then
        return 0
    fi

    tudo_log_literal 3 "\nRunning tudo_set_priority_dependent_variables with priority '$priority'"

    # Set PATH_TO_EXPORT
    # If priority equals "termux" then PATH_TO_EXPORT should be set to TERMUX_PRIORITY_PATH
    if [[ "$priority" == "termux" ]]; then
        PATH_TO_EXPORT="$TERMUX_PRIORITY_PATH"
    # If priority equals "android" then PATH_TO_EXPORT should be set to ANDROID_PRIORITY_PATH
    else
        PATH_TO_EXPORT="$ANDROID_PRIORITY_PATH"
    fi

    tudo_log 3 "PATH_TO_EXPORT='$PATH_TO_EXPORT'"


    # If priority equals "termux" then LD_LIBRARY_PATH_TO_EXPORT should be set to TERMUX_PRIORITY_LD_LIBRARY_PATH
    if [[ "$priority" == "termux" ]]; then
        LD_LIBRARY_PATH_TO_EXPORT="$TERMUX_PRIORITY_LD_LIBRARY_PATH"
    # If priority equals "android" then LD_LIBRARY_PATH_TO_EXPORT should be set to ANDROID_PRIORITY_LD_LIBRARY_PATH
    else
        LD_LIBRARY_PATH_TO_EXPORT="$ANDROID_PRIORITY_LD_LIBRARY_PATH"
    fi

    tudo_log 3 "LD_LIBRARY_PATH_TO_EXPORT='$LD_LIBRARY_PATH_TO_EXPORT'"


    # If priority equals "termux" then LD_PRELOAD_COMMAND should be set to TERMUX_PRIORITY_LD_PRELOAD_COMMAND
    if [[ "$priority" == "termux" ]]; then
        LD_PRELOAD_COMMAND="$TERMUX_PRIORITY_LD_PRELOAD_COMMAND"
    # If priority equals "android" then LD_PRELOAD_COMMAND should be set to ANDROID_PRIORITY_LD_PRELOAD_COMMAND
    else
        LD_PRELOAD_COMMAND="$ANDROID_PRIORITY_LD_PRELOAD_COMMAND"
    fi

    tudo_log 3 "LD_PRELOAD_COMMAND='$LD_PRELOAD_COMMAND'"


    previous_priority_dependent_variables_priortiy="$priority"

    return 0

}

tudo_add_export_or_unset_var_command() {

    local var_to_update="$1"
    local var_to_export="$2"
    local var_value="$3"

    if [ -n "$var_value" ]; then
        printf -v "$var_to_update" "%s" "${!var_to_update}export $var_to_export='${var_value//\'/\'\\\'\'}';"$'\n'
    else
        # Do not export empty variable as it will appear in environ
        # And unset it if it already exists
        printf -v "$var_to_update" "%s" "${!var_to_update}unset $var_to_export;"$'\n'
    fi

}

tudo_set_pre_tudo_shell_commands_to_run() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_set_pre_tudo_shell_commands_to_run"

    local priority

    # Set PRE_TUDO_SHELL_COMMANDS_TO_RUN with priority to required bin and library paths

    # If COMMAND_TYPE equals "su"
    if [[ "$COMMAND_TYPE" == "su" ]]; then
        priority="termux"
        tudo_log 3 "Setting PRE_TUDO_SHELL_COMMANDS_TO_RUN with priority to 'termux' bin and library paths for COMMAND_TYPE 'su'"

    # If COMMAND_TYPE equals "asu"
    elif [[ "$COMMAND_TYPE" == "asu" ]]; then
        priority="android"
        tudo_log 3 "Setting PRE_TUDO_SHELL_COMMANDS_TO_RUN with priority to 'android' bin and library paths for COMMAND_TYPE 'asu'"

    # If COMMAND_TYPE equals "path"
    elif [[ "$COMMAND_TYPE" == "path" ]]; then
        # If PATH_PRIORITY is android or termux
        if [[ "$PATH_PRIORITY" == "android" ]] || [[ "$PATH_PRIORITY" == "termux" ]]; then
            priority="$PATH_PRIORITY"
            tudo_log 3 "Setting PRE_TUDO_SHELL_COMMANDS_TO_RUN with priority to '$priority' bin and library paths for COMMAND_TYPE 'path' since PATH_PRIORITY is '$PATH_PRIORITY'"
        # If PATH_PRIORITY is default
        else
            # If TUDO_CANONICAL_PATH_COMMAND is under termux rootfs
            if [[ "$TUDO_CANONICAL_PATH_COMMAND" == "$TERMUX_ROOTFS"/* ]]; then
                priority="termux"
                tudo_log 3 "Setting PRE_TUDO_SHELL_COMMANDS_TO_RUN with priority to 'termux' bin and library paths for COMMAND_TYPE 'path' since TUDO_PATH_COMMAND is under termux rootfs"
            else
                priority="android"
                tudo_log 3 "Setting PRE_TUDO_SHELL_COMMANDS_TO_RUN with priority to 'android' bin and library paths for COMMAND_TYPE 'path' since TUDO_PATH_COMMAND is not under termux rootfs"
            fi
        fi

    # If COMMAND_TYPE equals "script"
    else
        # If PATH_PRIORITY is android
        if [[ "$PATH_PRIORITY" == "android" ]]; then
            priority="android"
        # If PATH_PRIORITY is default or termux
        else
            priority="termux"
        fi
        tudo_log 3 "Setting PRE_TUDO_SHELL_COMMANDS_TO_RUN with priority to $priority bin and library paths for COMMAND_TYPE 'script' since PATH_PRIORITY is '$PATH_PRIORITY'"
    fi

    # Set priority_dependent_variables with new priority if needed
    tudo_set_priority_dependent_variables "$priority" || return $?

    # Set PRE_TUDO_SHELL_COMMANDS_TO_RUN
    # Set variables that need to be exported when running the tudo shell
    PRE_TUDO_SHELL_COMMANDS_TO_RUN=""

    PRE_TUDO_SHELL_COMMANDS_TO_RUN+="export PATH='${PATH_TO_EXPORT//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_SHELL_COMMANDS_TO_RUN+="export TUDO__TERMUX_PRIORITY_PATH='${TERMUX_PRIORITY_PATH//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_SHELL_COMMANDS_TO_RUN+="export TUDO__ANDROID_PRIORITY_PATH='${ANDROID_PRIORITY_PATH//\'/\'\\\'\'}';"$'\n'

    tudo_add_export_or_unset_var_command "PRE_TUDO_SHELL_COMMANDS_TO_RUN" "LD_LIBRARY_PATH" "$LD_LIBRARY_PATH_TO_EXPORT" || return $?
    tudo_add_export_or_unset_var_command "PRE_TUDO_SHELL_COMMANDS_TO_RUN" "TUDO__TERMUX_PRIORITY_LD_LIBRARY_PATH" "$TERMUX_PRIORITY_LD_LIBRARY_PATH" || return $?
    tudo_add_export_or_unset_var_command "PRE_TUDO_SHELL_COMMANDS_TO_RUN" "TUDO__ANDROID_PRIORITY_LD_LIBRARY_PATH" "$ANDROID_PRIORITY_LD_LIBRARY_PATH" || return $?
   
    PRE_TUDO_SHELL_COMMANDS_TO_RUN+="export ${TERMUX_ENV__S_TERMUX}ROOTFS='${TERMUX_ROOTFS//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_SHELL_COMMANDS_TO_RUN+="export ${TERMUX_ENV__S_TERMUX}HOME='${TERMUX_HOME//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_SHELL_COMMANDS_TO_RUN+="export ${TERMUX_ENV__S_TERMUX}PREFIX='${TERMUX_PREFIX//\'/\'\\\'\'}';"$'\n'
    # If `$PREFIX` already exported when running `tudo`, only then export it
    [[ ! "$PREFIX" =~ $VALID_ROOTFS_OR_ABSOLUTE_PATH_REGEX ]] && \
        PRE_TUDO_SHELL_COMMANDS_TO_RUN+="export PREFIX='${TERMUX_PREFIX//\'/\'\\\'\'}';"$'\n'

    PRE_TUDO_SHELL_COMMANDS_TO_RUN+="export TMPDIR='${TMPDIR//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_SHELL_COMMANDS_TO_RUN+="export HOME='${TUDO_SHELL_HOME//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_SHELL_COMMANDS_TO_RUN+="export TERM='${TERM//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_SHELL_COMMANDS_TO_RUN+="export LANG='${LANG//\'/\'\\\'\'}';"$'\n'

    # If COMMAND_TYPE equals "script" and DISABLE_STDIN_FOR_CORE_SCRIPT is enabled
    if [[ "$COMMAND_TYPE" == "script" ]] && [[ "$DISABLE_STDIN_FOR_CORE_SCRIPT" == "1" ]]; then
        # Unset PS1 so that scripts run by script shells can check that interactive shell is not available
        PRE_TUDO_SHELL_COMMANDS_TO_RUN+="unset PS1;"$'\n'
    else
        PRE_TUDO_SHELL_COMMANDS_TO_RUN+="export PS1='${TUDO_SHELL_PS1//\'/\'\\\'\'}';"$'\n'
    fi

    # If LD_PRELOAD_COMMAND is not empty, then append it to PRE_TUDO_SHELL_COMMANDS_TO_RUN
    if [ -n "$LD_PRELOAD_COMMAND" ]; then
        PRE_TUDO_SHELL_COMMANDS_TO_RUN+="$LD_PRELOAD_COMMAND"$'\n'
    fi
    PRE_TUDO_SHELL_COMMANDS_TO_RUN+="export TUDO__TERMUX_LD_PRELOAD='${TERMUX_LD_PRELOAD//\'/\'\\\'\'}';"$'\n'

    # If TUDO_SHELL_RCFILE_COMMANDS is not empty, then append it to PRE_TUDO_SHELL_COMMANDS_TO_RUN
    if [ -n "$TUDO_SHELL_RCFILE_COMMANDS" ]; then
        PRE_TUDO_SHELL_COMMANDS_TO_RUN+="$TUDO_SHELL_RCFILE_COMMANDS"$'\n'
    fi

    # If TUDO_SHELL_HISTFILE_COMMANDS is not empty, then append it to PRE_TUDO_SHELL_COMMANDS_TO_RUN
    if [ -n "$TUDO_SHELL_HISTFILE_COMMANDS" ]; then
        PRE_TUDO_SHELL_COMMANDS_TO_RUN+="$TUDO_SHELL_HISTFILE_COMMANDS"$'\n'
    fi

    # If SET_TUDO_SHELL_TERMINAL_TITLE is enabled and stdout is available, then add command to set terminal title to PRE_TUDO_SHELL_COMMANDS_TO_RUN
    if [[ "$SET_TUDO_SHELL_TERMINAL_TITLE" == "1" ]] && [ -t 1 ]; then
        PRE_TUDO_SHELL_COMMANDS_TO_RUN+='echo -ne "\e]0;'"$TUDO_SHELL_TERMINAL_TITLE"'\a";'$'\n'
    fi

    # If TUDO_SHELL_WORKING_DIR is set, then append cd command to PRE_TUDO_SHELL_COMMANDS_TO_RUN
    if [ -n "$TUDO_SHELL_WORKING_DIR" ]; then
        PRE_TUDO_SHELL_COMMANDS_TO_RUN+="cd -- '${TUDO_SHELL_WORKING_DIR//\'/\'\\\'\'}';"$'\n'
    fi

    # If COMMAND_TYPE equals "su", "asu" or "path"
    if [[ "$COMMAND_TYPE" == "su" ]] || [[ "$COMMAND_TYPE" == "asu" ]] || [[ "$COMMAND_TYPE" == "path" ]]; then
        # If ADDITIONAL_TUDO_SHELL_PRE_COMMANDS_TO_RUN is not empty, then append it to PRE_TUDO_SHELL_COMMANDS_TO_RUN
        if [ -n "$ADDITIONAL_TUDO_SHELL_PRE_COMMANDS_TO_RUN" ]; then
            PRE_TUDO_SHELL_COMMANDS_TO_RUN+="$ADDITIONAL_TUDO_SHELL_PRE_COMMANDS_TO_RUN"$'\n\n'
        fi
    fi

    #tudo_log 3 $'\n'"PRE_TUDO_SHELL_COMMANDS_TO_RUN='$PRE_TUDO_SHELL_COMMANDS_TO_RUN'"

    return 0

}

tudo_set_pre_tudo_post_shell_commands_to_run() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_set_pre_tudo_post_shell_commands_to_run"

    # Set PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN with priority to termux paths
    tudo_log_literal 3 "\nSetting PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN with priority to termux paths"
    local priority="termux"

    # Set priority_dependent_variables with new priority if needed
    tudo_set_priority_dependent_variables "$priority" || return $?

    # Set PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN
    # Set variables that need to be exported when running the tudo post shell
    PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN=""

    PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="export PATH='${PATH_TO_EXPORT//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="export TUDO__TERMUX_PRIORITY_PATH='${TERMUX_PRIORITY_PATH//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="export TUDO__ANDROID_PRIORITY_PATH='${ANDROID_PRIORITY_PATH//\'/\'\\\'\'}';"$'\n'

    tudo_add_export_or_unset_var_command "PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN" "LD_LIBRARY_PATH" "$LD_LIBRARY_PATH_TO_EXPORT" || return $?
    tudo_add_export_or_unset_var_command "PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN" "TUDO__TERMUX_PRIORITY_LD_LIBRARY_PATH" "$TERMUX_PRIORITY_LD_LIBRARY_PATH" || return $?
    tudo_add_export_or_unset_var_command "PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN" "TUDO__ANDROID_PRIORITY_LD_LIBRARY_PATH" "$ANDROID_PRIORITY_LD_LIBRARY_PATH" || return $?

    PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="export ${TERMUX_ENV__S_TERMUX}ROOTFS='${TERMUX_ROOTFS//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="export ${TERMUX_ENV__S_TERMUX}HOME='${TERMUX_HOME//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="export ${TERMUX_ENV__S_TERMUX}PREFIX='${TERMUX_PREFIX//\'/\'\\\'\'}';"$'\n'
    # If `$PREFIX` already exported when running `tudo`, only then export it
    [[ ! "$PREFIX" =~ $VALID_ROOTFS_OR_ABSOLUTE_PATH_REGEX ]] && \
        PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="export PREFIX='${TERMUX_PREFIX//\'/\'\\\'\'}';"$'\n'

    PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="export TMPDIR='${TMPDIR//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="export HOME='${TUDO_POST_SHELL_HOME//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="export TERM='${TERM//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="export LANG='${LANG//\'/\'\\\'\'}';"$'\n'
    PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="export PS1='${TUDO_POST_SHELL_PS1//\'/\'\\\'\'}';"$'\n'

    # If LD_PRELOAD_COMMAND is not empty, then append it to PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN
    if [ -n "$LD_PRELOAD_COMMAND" ]; then
        PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="$LD_PRELOAD_COMMAND"$'\n'
    fi
    PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="export TUDO__TERMUX_LD_PRELOAD='${TERMUX_LD_PRELOAD//\'/\'\\\'\'}';"$'\n'

    # If TUDO_POST_SHELL_RCFILE_COMMANDS is not empty, then append it to PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN
    if [ -n "$TUDO_POST_SHELL_RCFILE_COMMANDS" ]; then
        PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="$TUDO_POST_SHELL_RCFILE_COMMANDS"$'\n'
    fi

    # If TUDO_POST_SHELL_HISTFILE_COMMANDS is not empty, then append it to PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN
    if [ -n "$TUDO_POST_SHELL_HISTFILE_COMMANDS" ]; then
        PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN+="$TUDO_POST_SHELL_HISTFILE_COMMANDS"$'\n'
    fi

    #tudo_log 3 $'\n'"PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN='$PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN'"

    return 0

}

tudo_set_tudo_command_path() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_set_tudo_command_path"

    TUDO_PATH_COMMAND="${TUDO_COMMAND[0]}"

    tudo_log 2 "TUDO_PATH_COMMAND='$TUDO_PATH_COMMAND'"

    # If TUDO_PATH_COMMAND is empty
    if [ -z "$TUDO_PATH_COMMAND" ]; then
        tudo_log_errors "The tudo command path '$TUDO_PATH_COMMAND' is empty"
        return 1
    fi

    # If PATH_PRIORITY is android
    if [[ "$PATH_PRIORITY" == "android" ]]; then
        # Set priority_dependent_variables to android for PATH_TO_EXPORT used by the tudo_find_absolute_path_for_executable_and_validate function
        # We do this now and later in the tudo_set_pre_tudo_shell_commands_to_run function as well once the final TUDO_PATH_COMMAND has been set
        tudo_set_priority_dependent_variables "android" || return $?
    fi

    # Find the absolute path for TUDO_PATH_COMMAND that should be used and validate it
    # TUDO_PATH_COMMAND is either considered an absolute path, otherwise searched for in current working directory or in all the paths in $PATH_TO_EXPORT variable
    tudo_find_absolute_path_for_executable_and_validate "TUDO_ABSOLUTE_PATH_COMMAND" "TUDO_PATH_COMMAND" "$TUDO_PATH_COMMAND" "$PATH_TO_EXPORT" "$TERMUX_PREFIX" "$TERMUX_HOME"
    return_value=$?
    if [ $return_value -ne 0 ] && [ $return_value -ne 112 ]; then
        tudo_log_errors "Failure while running 'tudo_find_absolute_path_for_executable_and_validate'"
        return $return_value
    elif [ $return_value -eq 112 ]; then
        tudo_log_errors "Command '$TUDO_PATH_COMMAND' not found"
        tudo_log_errors "Check your spelling and try again"
        return 1
    fi

    TUDO_PATH_COMMAND="$TUDO_ABSOLUTE_PATH_COMMAND"

    tudo_log 2 "TUDO_ABSOLUTE_PATH_COMMAND='$TUDO_ABSOLUTE_PATH_COMMAND'"

    # If TUDO_PATH_COMMAND is not a valid absolute path
    if [[ ! "$TUDO_PATH_COMMAND" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        tudo_log_errors "The TUDO_PATH_COMMAND '$TUDO_PATH_COMMAND' is not a valid absolute path"
        return 1
    fi


    # If PATH_PRIORITY is default
    if [[ "$PATH_PRIORITY" != "android" ]] && [[ "$PATH_PRIORITY" != "termux" ]]; then
        # Find canonical path to be used for setting priority in tudo_set_pre_tudo_shell_commands_to_run
        TUDO_CANONICAL_PATH_COMMAND="$(readlink -m -- "$TUDO_ABSOLUTE_PATH_COMMAND")"
        return_value=$?
        if [ $return_value -ne 0 ] || [[ ! "$TUDO_CANONICAL_PATH_COMMAND" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
            tudo_log_errors "Failure while finding canonical path to tudo path commmand"
            tudo_log_errors "TUDO_CANONICAL_PATH_COMMAND='$TUDO_CANONICAL_PATH_COMMAND'"
            if [ $return_value -eq 0 ]; then
                return_value=1
            fi
            return $return_value
        fi

        if [[ "$TUDO_CANONICAL_PATH_COMMAND" != "$TUDO_ABSOLUTE_PATH_COMMAND" ]]; then
            tudo_log 2 "TUDO_CANONICAL_PATH_COMMAND='$TUDO_CANONICAL_PATH_COMMAND'"
        fi
    fi

    return 0

}

tudo_set_tudo_path_command() {

    local return_value

    tudo_log_literal 3 "\n\n\nRunning tudo_set_tudo_path_command"

    # If TUDO_COMMAND is not set
    if [ ${#TUDO_COMMAND[@]} -eq 0 ]; then
        tudo_log_errors "TUDO_COMMAND is not set while running 'tudo_set_tudo_path_command'"
        return 1
    fi

    tudo_log 3 "TUDO_COMMAND_ARRAY_COUNT='${#TUDO_COMMAND[@]}'"

    tudo_log 3 $'\n'"TUDO_PATH_COMMAND=\`$TUDO_PATH_COMMAND\`"

    TUDO_PATH_COMMAND_TO_RUN=""

    # If "su" binary is being run, then unset LD_PRELOAD and LD_LIBRARY_PATH
    # if only "su" was passed without the '-a' option and current directory
    # did not have the "su" binary, then the wrapper script by termux at
    # $PREFIX/bin/su would ideally have been chosen by
    # the tudo_set_tudo_command_path function as TUDO_PATH_COMMAND, in
    # which case the wrapper script would ideally also automatically
    # unset the variables
    if [[ "$TUDO_PATH_COMMAND" == *"/su" ]]; then
        TUDO_PATH_COMMAND_TO_RUN="unset LD_PRELOAD; unset LD_LIBRARY_PATH; "
    fi

    # If TUDO_COMMAND argument size is 1, then only a path was passed to be executed
    if [ ${#TUDO_COMMAND[@]} -eq 1 ]; then

        TUDO_PATH_COMMAND_TO_RUN+="'${TUDO_PATH_COMMAND//\'/\'\\\'\'}'"
    # Else path was passed as $1, followed by arguments that should be passed to the path
    else
        TUDO_COMMAND=("${TUDO_COMMAND[@]:1}") # Remove first element since its the unparsed TUDO_PATH_COMMAND

        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
        if [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
            tudo_log 3 "Processing TUDO_PATH_COMMAND_ARGS array as per RUN_COMMAND intent rules"
        fi

        for i in "${!TUDO_COMMAND[@]}"; do
            # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
            if [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                # Replace any COMMA_ALTERNATIVE characters with normal commas `,` that exist in {TUDO_COMMAND[$i]}
                if [[ "${TUDO_COMMAND[$i]}" == *"$COMMA_ALTERNATIVE"* ]]; then
                    tudo_log 3 "COMMA_ALTERNATIVE found in TUDO_PATH_COMMAND_ARG $((i+1))"
                    tudo_replace_comma_alternative_chars_with_commas_in_string "TUDO_COMMAND[$i]" "${TUDO_COMMAND[$i]}"
                fi
            fi

            # If DISABLE_ARGUMENTS_LOGGING is not enabled
            if [[ "$DISABLE_ARGUMENTS_LOGGING" != "1" ]]; then
                tudo_log 3 "TUDO_PATH_COMMAND_ARG $((i+1))=\`${TUDO_COMMAND[$i]}\`"$'\n'
            fi
        done

        printf -v "TUDO_PATH_COMMAND_ARGS" "%q " "${TUDO_COMMAND[@]}"
        TUDO_PATH_COMMAND_ARGS="${TUDO_PATH_COMMAND_ARGS% }" # Remove trailing space

        TUDO_PATH_COMMAND_ARGS_LENGTH="${#TUDO_PATH_COMMAND_ARGS}"
        tudo_log 3 "TUDO_PATH_COMMAND_ARGS_LENGTH='$TUDO_PATH_COMMAND_ARGS_LENGTH'"


        # The `path` would not contribute much to crossing ARG_MAX since its only a path to a file, unless the path is too long
        # The ARG_MAX would be a concern only when arguments to `path` are passed via process substitution to the tudo script
        # and not as a direct argument since in that case ARG_MAX would have crossed at the point instead
        # If TUDO_PATH_COMMAND_ARGS_LENGTH is greater than TUDO_ARG_MAX_SAFE_LIMIT
        if [[ "$TUDO_PATH_COMMAND_ARGS_LENGTH" -gt "$TUDO_ARG_MAX_SAFE_LIMIT" ]]; then
            tudo_log 2 "Warning! The TUDO_PATH_COMMAND_ARGS_LENGTH '$TUDO_PATH_COMMAND_ARGS_LENGTH' is greater than $((TUDO_ARG_MAX_SAFE_LIMIT / 1024))KB. This may cause an 'Argument list too long' exception."
        fi

        # Pass TUDO_PATH_COMMAND_ARGS to TUDO_PATH_COMMAND
        TUDO_PATH_COMMAND_TO_RUN+="'${TUDO_PATH_COMMAND//\'/\'\\\'\'}' $TUDO_PATH_COMMAND_ARGS"
    fi

    # If DISABLE_ARGUMENTS_LOGGING is not enabled
    if [[ "$DISABLE_ARGUMENTS_LOGGING" != "1" ]]; then
        tudo_log 3 $'\n'"TUDO_PATH_COMMAND_TO_RUN=\`$TUDO_PATH_COMMAND_TO_RUN\`"
    fi

    return 0

}

tudo_set_tudo_script_command() {

    local return_value

    tudo_log_literal 3 "\n\n\nRunning tudo_set_tudo_script_command"

    TUDO_SCRIPT_COMMAND_TO_RUN=$'\n'

    # Append PRE_TUDO_SHELL_COMMANDS_TO_RUN to TUDO_SCRIPT_COMMAND_TO_RUN
    TUDO_SCRIPT_COMMAND_TO_RUN+="$PRE_TUDO_SHELL_COMMANDS_TO_RUN"$'\n\n'

    # If ADDITIONAL_TUDO_SHELL_PRE_COMMANDS_TO_RUN is not empty, then append it to TUDO_SCRIPT_COMMAND_TO_RUN
    if [ -n "$ADDITIONAL_TUDO_SHELL_PRE_COMMANDS_TO_RUN" ]; then
        TUDO_SCRIPT_COMMAND_TO_RUN+="$ADDITIONAL_TUDO_SHELL_PRE_COMMANDS_TO_RUN"$'\n\n'
    fi

    tudo_log 3 "TUDO_COMMAND_ARRAY_COUNT='${#TUDO_COMMAND[@]}'"

    # If TUDO_CORE_SCRIPT or arguments are passed and TUDO_CORE_SCRIPT is not empty
    # The TUDO_CORE_SCRIPT can optionally not be passed or passed as an empty string so that other "features"
    # of the "script" COMMAND_TYPE can still be used
    if [ ${#TUDO_COMMAND[@]} -ne 0 ] && [ -n "${TUDO_COMMAND[0]}" ]; then

        tudo_log 3 ""

        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
        if [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
            tudo_log 3 "Processing TUDO_CORE_SCRIPT and TUDO_CORE_SCRIPT_COMMAND_ARGS array as per RUN_COMMAND intent rules"
        fi

        for i in "${!TUDO_COMMAND[@]}"; do
            # If its the TUDO_CORE_SCRIPT argument and DECODE_CORE_SCRIPT_CONTENT or CORE_SCRIPT_IS_PATH_TO_SCRIPT_FILE is enabled
            if [ "$i" -eq 0 ] && { [[ "$DECODE_CORE_SCRIPT_CONTENT" == "1" ]] ||  [[ "$CORE_SCRIPT_IS_PATH_TO_SCRIPT_FILE" == "1" ]]; }; then
                # The TUDO_COMMAND[1] contains encoded data or a path to a file so no need to process it
                continue
            fi

            # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
            if [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                # Replace any COMMA_ALTERNATIVE characters with normal commas `,` that exist in {TUDO_COMMAND[$i]}
                if [[ "${TUDO_COMMAND[$i]}" == *"$COMMA_ALTERNATIVE"* ]]; then
                    # If its the TUDO_CORE_SCRIPT argument
                    if [ "$i" -eq 0 ]; then
                        tudo_log 3 "COMMA_ALTERNATIVE found in TUDO_CORE_SCRIPT"
                    else
                        tudo_log 3 "COMMA_ALTERNATIVE found in TUDO_CORE_SCRIPT_COMMAND_ARG $((i+1))"
                    fi
                    tudo_replace_comma_alternative_chars_with_commas_in_string "TUDO_COMMAND[$i]" "${TUDO_COMMAND[$i]}"
                fi
            fi

            # If DISABLE_ARGUMENTS_LOGGING is not enabled
            if [[ "$DISABLE_ARGUMENTS_LOGGING" != "1" ]]; then
                # If its the TUDO_CORE_SCRIPT argument
                if [ "$i" -eq 0 ]; then
                    tudo_log 3 "TUDO_CORE_SCRIPT=\`${TUDO_COMMAND[$i]}\`"$'\n'
                # Else TUDO_CORE_SCRIPT was passed as $1, followed by arguments that should be passed to the script
                else
                    tudo_log 3 "TUDO_CORE_SCRIPT_COMMAND_ARG $((i+1))=\`${TUDO_COMMAND[$i]}\`"$'\n'
                fi
            fi
        done

        # Set the first argument as TUDO_CORE_SCRIPT
        TUDO_CORE_SCRIPT="${TUDO_COMMAND[0]}"

        # If TUDO_CORE_SCRIPT_TEMP_FILENAME is empty, then use default
        if [ -z "$TUDO_CORE_SCRIPT_TEMP_FILENAME" ]; then
            TUDO_CORE_SCRIPT_TEMP_FILENAME="tudo_script__core_script"
        else
            # Else if user passed the filename with --script-name' option, then
            # strip longest match of */ from start, to remove any directory path passed and keep only the basename
            TUDO_CORE_SCRIPT_TEMP_FILENAME="${TUDO_CORE_SCRIPT_TEMP_FILENAME##*/}"
            # If empty, then use default
            TUDO_CORE_SCRIPT_TEMP_FILENAME="${TUDO_CORE_SCRIPT_TEMP_FILENAME:-tudo_script__core_script}"
        fi

        # Start a new TUDO_SHELL script shell and pass TUDO_CORE_SCRIPT to it
        # The SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL will contain the TUDO_CORE_SCRIPT argument that will be passed to the TUDO_SHELL
        # The way the TUDO_CORE_SCRIPT argument will be passed will depend on script shell capabilities and the options set
        # tudo_set_script_argument_for_script_shell shell_basename heredoc_word heredoc_word_quote script_is_path_to_script_file force_use_temp_script_file decode_script_content script_file_label script_file_name script_file_path/script_content
        tudo_set_script_argument_for_script_shell "$TUDO_SHELL_BASENAME" "TUDO_SCRIPT__CORE_SCRIPT_EOF" "'" "$CORE_SCRIPT_IS_PATH_TO_SCRIPT_FILE" "$FORCE_USE_TEMP_SCRIPT_FILE_FOR_CORE_SCRIPT" "$DECODE_CORE_SCRIPT_CONTENT" "TUDO_CORE_SCRIPT" "$TUDO_CORE_SCRIPT_TEMP_FILENAME" "$TUDO_CORE_SCRIPT"
        return_value=$?
        if [ $return_value -ne 0 ]; then
            tudo_log_errors "Failed to create TUDO_CORE_SCRIPT argument commands to pass them to TUDO_SHELL '$TUDO_SHELL'"
            return $return_value
        fi

        # Pass the SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL set by tudo_set_script_argument_for_script_shell to TUDO_SHELL
        printf -v "TUDO_SHELL_COMMAND_STRING" "$TUDO_SHELL_COMMAND_PRINT_FORMAT" "${TUDO_SHELL_COMMAND[@]}"
        TUDO_CORE_SCRIPT_COMMAND_TO_RUN="$TUDO_SHELL_COMMAND_STRING$SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL"

        # If arguments need to be passed to TUDO_CORE_SCRIPT
        if [ ${#TUDO_COMMAND[@]} -gt 1 ]; then
            TUDO_COMMAND=("${TUDO_COMMAND[@]:1}") # Remove first element since its the script

            printf -v "TUDO_CORE_SCRIPT_COMMAND_ARGS" "%q " "${TUDO_COMMAND[@]}"
            TUDO_CORE_SCRIPT_COMMAND_ARGS="${TUDO_CORE_SCRIPT_COMMAND_ARGS% }" # Remove trailing space

            TUDO_CORE_SCRIPT_COMMAND_ARGS_LENGTH="${#TUDO_CORE_SCRIPT_COMMAND_ARGS}"
            tudo_log 3 "TUDO_CORE_SCRIPT_COMMAND_ARGS_LENGTH='$TUDO_CORE_SCRIPT_COMMAND_ARGS_LENGTH'"

            # The `core_script` would not contribute much to crossing ARG_MAX since its either passed with process substitution or
            # as a path to a file storing it, unless the path is too long
            # The ARG_MAX would be a concern only when arguments to `core_script` are passed via process substitution to the tudo script
            # and not as a direct argument since in that case ARG_MAX would have crossed at the point instead
            # If TUDO_CORE_SCRIPT_COMMAND_ARGS_LENGTH is greater than TUDO_ARG_MAX_SAFE_LIMIT
            if [[ "$TUDO_CORE_SCRIPT_COMMAND_ARGS_LENGTH" -gt "$TUDO_ARG_MAX_SAFE_LIMIT" ]]; then
                tudo_log 2 "Warning! The TUDO_CORE_SCRIPT_COMMAND_ARGS_LENGTH '$TUDO_CORE_SCRIPT_COMMAND_ARGS_LENGTH' is greater than $((TUDO_ARG_MAX_SAFE_LIMIT / 1024))KB. This may cause an 'Argument list too long' exception."
            fi

            # Pass the arguments to the TUDO_SHELL after the SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL
            TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=" $TUDO_CORE_SCRIPT_COMMAND_ARGS"
        fi

        # If TUDO_CORE_SCRIPT_REDIRECT_MODE or TUDO_SHELL_STDIN_STRING is set or
        # DISABLE_STDIN_FOR_CORE_SCRIPT or RUN_CORE_SCRIPT_IN_BACKGROUND is enabled
        if [ -n "$TUDO_CORE_SCRIPT_REDIRECT_MODE" ] || \
            [ -n "$TUDO_SHELL_STDIN_STRING" ] || \
                [[ "$DISABLE_STDIN_FOR_CORE_SCRIPT" == "1" ]] || \
                    [[ "$RUN_CORE_SCRIPT_IN_BACKGROUND" == "1" ]]; then
            # Surround TUDO_CORE_SCRIPT_COMMAND_TO_RUN with command grouping
            TUDO_CORE_SCRIPT_COMMAND_TO_RUN="{"$'\n\n'"$TUDO_CORE_SCRIPT_COMMAND_TO_RUN"$'\n\n''}'

            # If TUDO_CORE_SCRIPT_REDIRECT_MODE is set
            if [ -n "$TUDO_CORE_SCRIPT_REDIRECT_MODE" ]; then

                # If TUDO_CORE_SCRIPT_REDIRECT_MODE equal "0", then redirect stderr to stdout
                if [[ "$TUDO_CORE_SCRIPT_REDIRECT_MODE" == "0" ]]; then
                    TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' 2>&1'

                # Elif TUDO_CORE_SCRIPT_REDIRECT_MODE equal "1", then redirect stdout to stderr
                elif [[ "$TUDO_CORE_SCRIPT_REDIRECT_MODE" == "1" ]]; then
                    TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' 1>&2'

                # Elif TUDO_CORE_SCRIPT_REDIRECT_MODE equal "2", then redirect stdout to /dev/null
                elif [[ "$TUDO_CORE_SCRIPT_REDIRECT_MODE" == "2" ]]; then
                    TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' 1>/dev/null'

                # Elif TUDO_CORE_SCRIPT_REDIRECT_MODE equal "3", then redirect stderr to /dev/null
                elif [[ "$TUDO_CORE_SCRIPT_REDIRECT_MODE" == "3" ]]; then
                    TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' 2>/dev/null'

                # Elif TUDO_CORE_SCRIPT_REDIRECT_MODE equal "4", then redirect both stdout and stderr to /dev/null
                elif [[ "$TUDO_CORE_SCRIPT_REDIRECT_MODE" == "4" ]]; then
                    TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' &>/dev/null'

                # Elif TUDO_CORE_SCRIPT_REDIRECT_MODE equal "5", then redirect stderr to stdout and redirect stdout to stderr
                elif [[ "$TUDO_CORE_SCRIPT_REDIRECT_MODE" == "5" ]]; then
                    TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' 3>&2 2>&1 1>&3'

                # Elif TUDO_CORE_SCRIPT_REDIRECT_MODE equal "6", then redirect stderr to stdout and redirect stdout to /dev/null
                elif [[ "$TUDO_CORE_SCRIPT_REDIRECT_MODE" == "6" ]]; then
                    TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' 2>&1 1>/dev/null'

                # Else append TUDO_CORE_SCRIPT_REDIRECT_MODE to TUDO_CORE_SCRIPT_COMMAND_TO_RUN
                else
                    TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=" $TUDO_CORE_SCRIPT_REDIRECT_MODE"

                fi
            fi

            # If TUDO_SHELL_STDIN_STRING is set
            if [ -n "$TUDO_SHELL_STDIN_STRING" ]; then
                # If TUDO_SHELL_BASENAME is in TUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT
                if [[ " $TUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT " == *" $TUDO_SHELL_BASENAME "* ]]; then
                    # Pass TUDO_SHELL_STDIN_STRING as stdin with a herestring to TUDO_SHELL
                    TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' <<<'"'${TUDO_SHELL_STDIN_STRING//\'/\'\\\'\'}'"
                else
                    # Pass TUDO_SHELL_STDIN_STRING as stdin with process substitution to TUDO_SHELL
                    TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' < <(printf "%s" '"'${TUDO_SHELL_STDIN_STRING//\'/\'\\\'\'}'"')'
                fi
            else
                # If DISABLE_STDIN_FOR_CORE_SCRIPT is enabled, then redirect stdin to /dev/null
                if [[ "$DISABLE_STDIN_FOR_CORE_SCRIPT" == "1" ]]; then
                    TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' < /dev/null'
                fi
            fi

            # If RUN_CORE_SCRIPT_IN_BACKGROUND is enabled, then start TUDO_CORE_SCRIPT in background
            if [[ "$RUN_CORE_SCRIPT_IN_BACKGROUND" == "1" ]]; then
                TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=' &'
                TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=$'\n''export TUDO_SCRIPT__CORE_SCRIPT_PID=$!;'
                TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=$'\n''export TUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE=0;'
            fi

            TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=$'\n\n'
        fi

        # If RUN_CORE_SCRIPT_IN_BACKGROUND is not enabled
        if [[ "$RUN_CORE_SCRIPT_IN_BACKGROUND" != "1" ]]; then
            TUDO_CORE_SCRIPT_COMMAND_TO_RUN+=$'\n''export TUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE=$?;'$'\n\n'

            # If EXIT_EARLY_IF_CORE_SCRIPT_FAILS is enabled, then exit if TUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE does not equal 0
            if [[ "$EXIT_EARLY_IF_CORE_SCRIPT_FAILS" == "1" ]]; then
                TUDO_CORE_SCRIPT_COMMAND_TO_RUN+='[ $TUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE -ne 0 ] && exit $TUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE'$'\n\n'
            fi
        fi

        # Append TUDO_CORE_SCRIPT_COMMAND_TO_RUN to TUDO_SCRIPT_COMMAND_TO_RUN
        TUDO_SCRIPT_COMMAND_TO_RUN+="$TUDO_CORE_SCRIPT_COMMAND_TO_RUN"

    else
        # Append dummy TUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE to TUDO_SCRIPT_COMMAND_TO_RUN
        TUDO_SCRIPT_COMMAND_TO_RUN+='export TUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE=0;'$'\n\n'
    fi

    # If ADDITIONAL_TUDO_SHELL_POST_COMMANDS_TO_RUN is not empty, then append it to TUDO_SCRIPT_COMMAND_TO_RUN
    if [ -n "$ADDITIONAL_TUDO_SHELL_POST_COMMANDS_TO_RUN" ]; then
        TUDO_SCRIPT_COMMAND_TO_RUN+="$ADDITIONAL_TUDO_SHELL_POST_COMMANDS_TO_RUN"$'\n\n'
    fi

    # If GO_BACK_TO_LAST_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT is enabled, then simulate double back button press to go to the last activity, first to close keyboard and second to close terminal session
    if [[ "$GO_BACK_TO_LAST_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT" == "1" ]]; then
        TUDO_SCRIPT_COMMAND_TO_RUN+='$(export PATH="$ANDROID_PRIORITY_PATH"; export LD_LIBRARY_PATH="$ANDROID_PRIORITY_LD_LIBRARY_PATH"; unset LD_PRELOAD; input keyevent KEYCODE_BACK; input keyevent KEYCODE_BACK;);'$'\n\n'
    # If GO_TO_LAUNCHER_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT is enabled, then simulate home button press to go to the launcher activity
    elif [[ "$GO_TO_LAUNCHER_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT" == "1" ]]; then
        TUDO_SCRIPT_COMMAND_TO_RUN+='$(export PATH="$ANDROID_PRIORITY_PATH"; export LD_LIBRARY_PATH="$ANDROID_PRIORITY_LD_LIBRARY_PATH"; unset LD_PRELOAD; am start --user 0 -a android.intent.action.MAIN -c android.intent.category.HOME &>/dev/null;);'$'\n\n'
    fi

    # If CLEAR_SHELL_AFTER_RUNNING_CORE_SCRIPT is enabled, then add clear command
    if [[ "$CLEAR_SHELL_AFTER_RUNNING_CORE_SCRIPT" == "1" ]]; then
        TUDO_SCRIPT_COMMAND_TO_RUN+="clear"$'\n'
    fi

    # If RUN_INTERACTIVE_POST_TUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT is enabled, start a new interactive post shell
    # We do not check if stdout and stdin are available since tudo could be piped or redirected and may not be connected to a tty
    # The -t 0 and -t 1 checks fail if tudo is run in a simple subshell in android 10 but not on 7
    if [[ "$RUN_INTERACTIVE_POST_TUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT" == "1" ]]; then
        # Append PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN
        TUDO_SCRIPT_COMMAND_TO_RUN+="$PRE_TUDO_POST_SHELL_COMMANDS_TO_RUN"$'\n'

        # If ADDITIONAL_TUDO_POST_SHELL_PRE_COMMANDS_TO_RUN is not empty, then append it to TUDO_SCRIPT_COMMAND_TO_RUN
        if [ -n "$ADDITIONAL_TUDO_POST_SHELL_PRE_COMMANDS_TO_RUN" ]; then
            TUDO_SCRIPT_COMMAND_TO_RUN+="$ADDITIONAL_TUDO_POST_SHELL_PRE_COMMANDS_TO_RUN"$'\n'
        fi

        printf -v "TUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING" "$TUDO_POST_SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT" "${TUDO_POST_SHELL_INTERACTIVE_COMMAND[@]}"
        TUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING="${TUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING% }" # Remove trailing space

        # If TUDO_POST_SHELL_STDIN_STRING is set
        if [ -n "$TUDO_POST_SHELL_STDIN_STRING" ]; then
            # Surround TUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING with command grouping
            TUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING="{"$'\n\n'"$TUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING"$'\n\n''}'

            # If TUDO_POST_SHELL_BASENAME is in TUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT
            if [[ " $TUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT " == *" $TUDO_POST_SHELL_BASENAME "* ]]; then
                # Pass TUDO_POST_SHELL_STDIN_STRING as stdin with a herestring to TUDO_POST_SHELL
                TUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING+=' <<<'"'${TUDO_POST_SHELL_STDIN_STRING//\'/\'\\\'\'}'"
            else
                # Pass TUDO_POST_SHELL_STDIN_STRING as stdin with process substitution to TUDO_POST_SHELL
                TUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING+=' < <(printf "%s" '"'${TUDO_POST_SHELL_STDIN_STRING//\'/\'\\\'\'}'"')'
            fi
        fi

        TUDO_SCRIPT_COMMAND_TO_RUN+="$TUDO_POST_SHELL_INTERACTIVE_COMMAND_STRING"$'\n'

        # If ADDITIONAL_TUDO_POST_SHELL_POST_COMMANDS_TO_RUN is not empty, then append it to TUDO_SCRIPT_COMMAND_TO_RUN
        if [ -n "$ADDITIONAL_TUDO_POST_SHELL_POST_COMMANDS_TO_RUN" ]; then
            TUDO_SCRIPT_COMMAND_TO_RUN+="$ADDITIONAL_TUDO_POST_SHELL_POST_COMMANDS_TO_RUN"$'\n'
        fi
    else
        # Exit with exit code of TUDO_CORE_SCRIPT
        TUDO_SCRIPT_COMMAND_TO_RUN+='exit $TUDO_SCRIPT__CORE_SCRIPT_EXIT_CODE'$'\n'
    fi



    # Set TUDO_SCRIPT_COMMAND_TRAPS and TUDO_SCRIPT_COMMAND_TRAPS_REMOVE_TEMP_DIRECTORY_FUNCTION
    tudo_create_script_command_traps
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failed to create traps commands for TUDO_TEMP_DIRECTORY '$TUDO_TEMP_DIRECTORY'"
        return $return_value
    fi

    # If TUDO_SCRIPT_COMMAND_TRAPS is set
    if [ -n "$TUDO_SCRIPT_COMMAND_TRAPS" ]; then
        # If a script shell that doesn't support process substitution is being used or '-f' is passed, then
        # tudo_set_script_argument_for_script_shell_for_tudo will store temp core_script file at TUDO_CORE_SCRIPT_TEMP_FILENAME in TUDO_TEMP_DIRECTORY
        # add traps at start of TUDO_SCRIPT_COMMAND_TO_RUN to remove the TUDO_TEMP_DIRECTORY when the script exits
        TUDO_SCRIPT_COMMAND_TO_RUN=$'\n'"$TUDO_SCRIPT_COMMAND_TRAPS"$'\n'"$TUDO_SCRIPT_COMMAND_TO_RUN"
    fi

    # If DISABLE_ARGUMENTS_LOGGING is not enabled
    #if [[ "$DISABLE_ARGUMENTS_LOGGING" != "1" ]]; then
    #   tudo_log 3 $'\n'"TUDO_SCRIPT_COMMAND_TO_RUN=\`$TUDO_SCRIPT_COMMAND_TO_RUN\`"
    #fi

    return 0

}

##
# `tudo_set_script_argument_for_script_shell` `<shell_basename>` `<heredoc_word>` `<heredoc_word_quote>` `<script_is_path_to_script_file>` `<force_use_temp_script_file>` `<decode_script_content>` `<script_file_label>` `<script_file_name>` `<script_file_path>`/script_content
##
tudo_set_script_argument_for_script_shell() {

    local return_value

    # If argument count is not 9
    if [ $# -ne 9 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_set_script_argument_for_script_shell'"
        return 1
    fi

    local shell_basename="$1"
    local heredoc_word="$2"
    local heredoc_word_quote="$3"
    local script_is_path_to_script_file="$4"
    local force_use_temp_script_file="$5"
    local decode_script_content="$6"
    local script_file_label="$7"
    local script_file_name="$8"

    # If shell_basename is not in any of the TUDO_SUPPORTED_SCRIPT_SHELLS, then exit with error
    if [[ "$shell_basename" == *' '* ]] || [[ " $TUDO_SUPPORTED_SCRIPT_SHELLS " != *" $shell_basename "* ]]; then
        tudo_log_errors "The shell_basename '$shell_basename' while running 'tudo_set_script_argument_for_script_shell' is not supported. It must be one of '$TUDO_SUPPORTED_SCRIPT_SHELLS'"
        return 1
    fi

    SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL=""

    # If script_is_path_to_script_file is enabled, then just pass script_file_path as the argument to the script shell
    if [[ "$script_is_path_to_script_file" == "1" ]]; then
        local script_file_path="$9"

        tudo_log 3 "$script_file_label will be passed to the script shell as a path to a file"

        # Replace "$PREFIX/" or "~/" prefix with termux absolute paths in script_file_path
        tudo_expand_termux_path "script_file_path" "$script_file_label" "$script_file_path" "$TERMUX_PREFIX" "$TERMUX_HOME" 3
        return_value=$?
        if [ $return_value -ne 0 ]; then
            tudo_log_errors "Failed to expand $script_file_label '$script_file_path'"
            return $return_value
        fi

        # If script_file_path is not a valid absolute path
        if [[ ! "$script_file_path" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
            tudo_log_errors "The $script_file_label '$script_file_path' is not a valid absolute path"
            return 1
        fi

        tudo_log 3 "script_file_path='$script_file_path'"
        printf -v "script_file_path_string" "%q" "$script_file_path"
        SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL="$script_file_path_string"

    else
        local script_content="$9"

        # If shell is in TUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT (dash, sh, node, php)
        # or force_use_temp_script_file is enabled, then
        # store the script in a temp script file in TUDO_TEMP_DIRECTORY and pass that as argument to the script shell
        if [[ " $TUDO_SCRIPT_SHELLS_WITHOUT_PROCESS_SUBSTITUTION_SUPPORT " == *" $shell_basename "* ]] || [[ "$force_use_temp_script_file" == "1" ]]; then
            local log_content=1

            # If DISABLE_ARGUMENTS_LOGGING is enabled
            if [[ "$DISABLE_ARGUMENTS_LOGGING" == "1" ]]; then
                log_content=0
            fi

            tudo_log 3 "$script_file_label will be passed to the script shell after being store in a temp file"

            # Setup TUDO_TEMP_DIRECTORY
            tudo_setup_tudo_temp_directory
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "Failure while running 'tudo_setup_tudo_temp_directory'"
                return $return_value
            fi

            # If TUDO_TEMP_DIRECTORY is not a valid absolute path
            if [[ ! "$TUDO_TEMP_DIRECTORY" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
                tudo_log_errors "The TUDO_TEMP_DIRECTORY '$TUDO_TEMP_DIRECTORY' is not a valid absolute path, required by 'tudo_set_script_argument_for_script_shell'"
                return 1
            fi

            script_file="$TUDO_TEMP_DIRECTORY/$script_file_name"

            tudo_log 3 "$script_file_label temp file='$script_file'"

            # Tudo_create_tudo_temp_file label path log_content decode_content content
            tudo_create_tudo_temp_file "$script_file_label" "$script_file" "$log_content" "$decode_script_content" "$script_content"
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "Failure while running 'tudo_create_tudo_temp_file'"
                return $return_value
            fi

            printf -v "script_file_string" "%q" "$script_file"
            SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL="$script_file_string"

        # If shell is bash, zsh, fish, ksh, python python2, ruby, perl, lua5.2, lua5.3, lua5.4,
        # use process substitution with printf to pass script_content to the script shell.
        # Heredoc is not used since that will create a temp file in TMPDIR which is slower and less secure.
        # Note that ARG_MAX will not cross because of passing the script_content as an argument to printf
        # since printf is a shell built-in and exec is not done. It will however cross if an external call were to
        # be made to printf with `$PREFIX/bin/print`. The ARG_MAX would be a concern only when `core_script`
        # is passed via process substitution to the tudo script and not as a direct argument since in that
        # case ARG_MAX would have crossed at the point instead.
        elif [[ " bash zsh fish ksh python python2 ruby perl lua5.2 lua5.3 lua5.4 " == *" $shell_basename "* ]]; then

            tudo_log 3 "$script_file_label will be passed to the script shell using process substitution with printf command"

            SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL='<(printf "%s" '"'${script_content//\'/\'\\\'\'}
'"')'

            #tudo_log 3 "$script_file_label will be passed to the script shell using process substitution with a cat heredoc"

#           SCRIPT_ARGUMENT_FOR_SCRIPT_SHELL='<(cat <<'"$heredoc_word_quote$heredoc_word$heredoc_word_quote"'
#'"$script_content"'
#
#'"$heredoc_word"'
#)'


        else
            tudo_log_errors "shell_basename '$shell_basename' not handled while running 'tudo_set_script_argument_for_script_shell'"
            return 1
        fi
    fi

    return 0

}

##
# `tudo_create_tudo_temp_file` `<label>` `<path>` `<log_content>` `<decode_content>` `<content>`
##
tudo_create_tudo_temp_file() {

    local return_value

    # If argument count is not 5
    if [ $# -ne 5 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_create_tudo_temp_file'"
        return 1
    fi

    local label="$1"
    local path="$2"
    local log_content="$3"
    local decode_content="$4"
    local content="$5"

    # If path is not a valid absolute path
    if [[ ! "$path" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        tudo_log_errors "The '$label' file at path '$path' is not an absolute path"
        return 2
    fi

    # Write the contents to file at path
    # Decode first if required
    # Decoding of binary data needs to be done on the fly since
    # Binary data cannot be stored in a variable

    tudo_log 3 "Creating $label file at '$path'"

    if [[ "$decode_content" == "1" ]]; then
        printf '%s' "$content" | base64 -d > "$path"
    else
        printf '%s' "$content" > "$path"
    fi
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failure while creating $label file at '$path'"
        return $return_value
    fi

    # Read file at path again and log its content but only if binary data is not stored in it
    if [[ "$TUDO_LOG_LEVEL" -ge 2 ]] && [[ "$log_content" == "1" ]]  && [[ "$decode_content" != "1" ]]; then
        local file_contents=""
        file_contents="$(cat "$path")"
        tudo_log 2 $'\n'"${label}_CONTENTS=\`$file_contents\`"
    fi

    return 0

}

tudo_set_tudo_shell() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_set_tudo_shell"

    # If on Android `< 7`, and running `asu`/`script` commands with
    # `-A` or `-AA` flags, then default to Android system shell, as
    # Termux shells will have linker errors as `LD_LIBRARY_PATH` will
    # not be set, so only use/allow `/system/bin/sh` shell.

    # If TUDO_SHELL is set
    if [ -n "$TUDO_SHELL" ]; then
        tudo_trim_trailing_newlines "TUDO_SHELL" "$TUDO_SHELL"

        # Validate the TUDO_SHELL
        tudo_validate_shell "TUDO_SHELL" "TUDO_SHELL" "$TUDO_SHELL" "$TUDO_SUPPORTED_SHELLS" "$TERMUX_PREFIX" "$TERMUX_BIN" "$TERMUX_HOME"
        return_value=$?
        if [ $return_value -ne 0 ]; then
            tudo_log_errors "Failed to validate 'TUDO_SHELL'"
            return $return_value
        fi

        if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ] && \
                { [[ "$COMMAND_TYPE" == "asu" ]] || [[ "$COMMAND_TYPE" == "script" ]]; } && \
                [[ "$SET_SECONDARY_PRIORITY_PATHS" == "0" ]] && \
                [[ "$TUDO_SHELL" != "/system/bin/sh" ]]; then
            tudo_log_errors "The 'TUDO_SHELL' must be '/system/bin/sh' if running '$COMMAND_TYPE' command on Android '< 7'"
            return 1
        fi
    else
        # Default to bash as TUDO_SHELL
        TUDO_SHELL="$BASH_SHELL_PATH"

        if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ] && \
                { [[ "$COMMAND_TYPE" == "asu" ]] || [[ "$COMMAND_TYPE" == "script" ]]; } && \
                [[ "$SET_SECONDARY_PRIORITY_PATHS" == "0" ]]; then
            TUDO_SHELL="/system/bin/sh"
        fi
    fi

    # If TUDO_SHELL is not a valid absolute path
    if [[ ! "$TUDO_SHELL" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        tudo_log_errors "The TUDO_SHELL '$TUDO_SHELL' is not a valid absolute path"
        return 1
    fi

    tudo_log 2 "TUDO_SHELL='$TUDO_SHELL'"

    # Find the basename and parent directory of the TUDO_SHELL
    TUDO_SHELL_BASENAME="${TUDO_SHELL##*/}" # Strip longest match of */ from start
    TUDO_SHELL_PARENT_DIR="${TUDO_SHELL:0:${#TUDO_SHELL} - ${#TUDO_SHELL_BASENAME}}" # Substring from 0 to position of basename
    case "$TUDO_SHELL_PARENT_DIR" in *[!/]*/) TUDO_SHELL_PARENT_DIR="${TUDO_SHELL_PARENT_DIR%"${TUDO_SHELL_PARENT_DIR##*[!/]}"}";; *[/]) TUDO_SHELL_PARENT_DIR="/";; esac # Remove trailing slashes if not root

    tudo_log 3 "TUDO_SHELL_BASENAME='$TUDO_SHELL_BASENAME'"
    tudo_log 3 "TUDO_SHELL_PARENT_DIR='$TUDO_SHELL_PARENT_DIR'"

    # If TUDO_SHELL is not in any of the TUDO_SUPPORTED_SHELLS, then exit with error
    # The basename of the shell file could be faked but the actual shell inside the file is not checked
    if [[ "$TUDO_SHELL_BASENAME" == *' '* ]] || [[ " $TUDO_SUPPORTED_SHELLS " != *" $TUDO_SHELL_BASENAME "* ]]; then
        tudo_log_errors "The TUDO_SHELL '$TUDO_SHELL' is not supported. It must be one of '$TUDO_SUPPORTED_SHELLS'"
        return 1
    fi

    return 0

}

tudo_set_tudo_post_shell() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_set_tudo_post_shell"


    # If on Android `< 7`, and running `asu`/`script` commands with
    # `-A` or `-AA` flags, then default to Android system shell, as
    # Termux shells will have linker errors as `LD_LIBRARY_PATH` will
    # not be set, so only use/allow `/system/bin/sh` shell.

    # If TUDO_POST_SHELL is set
    if [ -n "$TUDO_POST_SHELL" ]; then
        tudo_trim_trailing_newlines "TUDO_POST_SHELL" "$TUDO_POST_SHELL"

        # Validate the TUDO_POST_SHELL
        tudo_validate_shell "TUDO_POST_SHELL" "TUDO_POST_SHELL" "$TUDO_POST_SHELL" "$TUDO_SUPPORTED_POST_SHELLS" "$TERMUX_PREFIX" "$TERMUX_BIN" "$TERMUX_HOME"
        return_value=$?
        if [ $return_value -ne 0 ]; then
            tudo_log_errors "Failed to validate 'TUDO_POST_SHELL'"
            return $return_value
        fi

        if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ] && \
                { [[ "$COMMAND_TYPE" == "asu" ]] || [[ "$COMMAND_TYPE" == "script" ]]; } && \
                [[ "$SET_SECONDARY_PRIORITY_PATHS" == "0" ]] && \
                [[ "$TUDO_POST_SHELL" != "/system/bin/sh" ]]; then
            tudo_log_errors "The 'TUDO_POST_SHELL' must be '/system/bin/sh' if running '$COMMAND_TYPE' command on Android '< 7'"
            return 1
        fi
    else
        # Default to bash as TUDO_POST_SHELL
        TUDO_POST_SHELL="$BASH_SHELL_PATH"

        if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ] && \
                { [[ "$COMMAND_TYPE" == "asu" ]] || [[ "$COMMAND_TYPE" == "script" ]]; } && \
                [[ "$SET_SECONDARY_PRIORITY_PATHS" == "0" ]]; then
            TUDO_POST_SHELL="/system/bin/sh"
        fi
    fi

    # If TUDO_POST_SHELL is not a valid absolute path
    if [[ ! "$TUDO_POST_SHELL" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        tudo_log_errors "The TUDO_POST_SHELL '$TUDO_POST_SHELL' is not a valid absolute path"
        return 1
    fi

    tudo_log 2 "TUDO_POST_SHELL='$TUDO_POST_SHELL'"

    # Find the basename and parent directory of the TUDO_POST_SHELL
    TUDO_POST_SHELL_BASENAME="${TUDO_POST_SHELL##*/}" # Strip longest match of */ from start
    TUDO_POST_SHELL_PARENT_DIR="${TUDO_POST_SHELL:0:${#TUDO_POST_SHELL} - ${#TUDO_POST_SHELL_BASENAME}}" # Substring from 0 to position of basename
    case "$TUDO_POST_SHELL_PARENT_DIR" in *[!/]*/) TUDO_POST_SHELL_PARENT_DIR="${TUDO_POST_SHELL_PARENT_DIR%"${TUDO_POST_SHELL_PARENT_DIR##*[!/]}"}";; *[/]) TUDO_POST_SHELL_PARENT_DIR="/";; esac # Remove trailing slashes if not root

    tudo_log 3 "TUDO_POST_SHELL_BASENAME='$TUDO_POST_SHELL_BASENAME'"
    tudo_log 3 "TUDO_POST_SHELL_PARENT_DIR='$TUDO_POST_SHELL_PARENT_DIR'"

    # If TUDO_POST_SHELL is not in any of the TUDO_SUPPORTED_SHELLS, then exit with error
    # The basename of the shell file could be faked but the actual shell inside the file is not checked
    if [[ "$TUDO_POST_SHELL_BASENAME" == *' '* ]] || [[ " $TUDO_SUPPORTED_POST_SHELLS " != *" $TUDO_POST_SHELL_BASENAME "* ]]; then
        tudo_log_errors "The TUDO_POST_SHELL '$TUDO_POST_SHELL' is not supported. It must be one of '$TUDO_SUPPORTED_POST_SHELLS'"
        return 1
    fi

    return 0

}

##
# `tudo_validate_shell` `<variable_name>` `<shell_label>` `<user_shell>` `<supported_shells>` `<termux_prefix>` `<termux_bin>` `<termux_home>`
##
tudo_validate_shell() {

    local return_value

    #if argument count is not 7
    if [ $# -ne 7 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_validate_shell'"
        return 1
    fi

    local variable_name="$1"
    local shell_label="$2"
    local user_shell="$3"
    local supported_shells="$4"
    local termux_prefix="$5"
    local termux_bin="$6"
    local termux_home="$7"

    local shell

    # If user_shell is set to a shell in supported_shells, then set user_shell to "$termux_bin/$user_shell"
    if [[ "$user_shell" != *'/'* ]]; then
        if [[ "$user_shell" != *' '* ]] && [[ " $supported_shells " == *" $user_shell "* ]]; then
            shell="$termux_bin/$user_shell"
        else
            tudo_log_errors "The $shell_label '$user_shell' is not supported. It must be one of '$supported_shells'"
            return 1
        fi
    else
        # Replace "$PREFIX/" or "~/" prefix with termux absolute paths in user_shell
        tudo_expand_termux_path "user_shell" "$shell_label" "$user_shell" "$termux_prefix" "$termux_home" 3
        return_value=$?
        if [ $return_value -ne 0 ]; then
            tudo_log_errors "Failed to expand $shell_label '$user_shell'"
            return $return_value
        fi

        shell="$user_shell"
    fi

    # tudo_run_file_type_tests_on_path label path log_file_tests_failure_errors show_stat_output_on_file_tests_failure check_if_absolute_path file_type_tests
    tudo_run_file_type_tests_on_path "$shell_label" "$shell" 1 1 1 "frx" || return $?


    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'

    # If variable_name does not equal "shell" and is valid bash variable_name
    if [[ "$variable_name" != "shell" ]] && [[ "$variable_name" =~ $valid_bash_variable_name_regex ]]; then
        # Set variable_name to shell
        printf -v "$variable_name" "%s" "$shell"
    else
        tudo_log_errors "variable_name '$1' passed to 'tudo_expand_termux_path' equals 'shell' or is not a valid bash variable name"
        return 1
    fi

}

tudo_set_tudo_shell_rcfile() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_set_tudo_shell_rcfile"

    # Set rcfile variables
    tudo_set_shell_rcfile "TUDO_SHELL" "$TUDO_SHELL_BASENAME" "$TUDO_SHELL_HOME" "$TUDO_SHELL_SHARE_RCFILES_AND_HISTFILES"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failure while running 'tudo_set_rcfile_functions' for TUDO_SHELL '$TUDO_SHELL'"
        return $return_value
    fi

    TUDO_SHELL_RCFILE="$SHELL_RCFILE"
    TUDO_SHELL_RCFILE_PARENT_DIR="$SHELL_RCFILE_PARENT_DIR"
    TUDO_SHELL_RCFILE_COMMANDS="$SHELL_RCFILE_COMMANDS"
    TUDO_SHELL_RCFILE_VALUE="$SHELL_RCFILE_VALUE"
    TUDO_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=("${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "${TUDO_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    tudo_log 3 "TUDO_SHELL_RCFILE='$TUDO_SHELL_RCFILE'"
    tudo_log 3 "TUDO_SHELL_RCFILE_PARENT_DIR='$TUDO_SHELL_RCFILE_PARENT_DIR'"
    tudo_log 3 "TUDO_SHELL_RCFILE_COMMANDS='$TUDO_SHELL_RCFILE_COMMANDS'"
    tudo_log 3 "TUDO_SHELL_RCFILE_VALUE=\`$TUDO_SHELL_RCFILE_VALUE\`"

    return 0

}

tudo_set_tudo_post_shell_rcfile() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_set_tudo_post_shell_rcfile"

    # Set rcfile variables
    tudo_set_shell_rcfile "TUDO_POST_SHELL" "$TUDO_POST_SHELL_BASENAME" "$TUDO_POST_SHELL_HOME" "$TUDO_POST_SHELL_SHARE_RCFILES_AND_HISTFILES"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failure while running 'tudo_set_rcfile_functions' for TUDO_POST_SHELL '$TUDO_POST_SHELL'"
        return $return_value
    fi

    TUDO_POST_SHELL_RCFILE="$SHELL_RCFILE"
    TUDO_POST_SHELL_RCFILE_PARENT_DIR="$SHELL_RCFILE_PARENT_DIR"
    TUDO_POST_SHELL_RCFILE_COMMANDS="$SHELL_RCFILE_COMMANDS"
    TUDO_POST_SHELL_RCFILE_VALUE="$SHELL_RCFILE_VALUE"
    TUDO_POST_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=("${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "${TUDO_POST_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    tudo_log 3 "TUDO_POST_SHELL_RCFILE='$TUDO_POST_SHELL_RCFILE'"
    tudo_log 3 "TUDO_POST_SHELL_RCFILE_PARENT_DIR='$TUDO_POST_SHELL_RCFILE_PARENT_DIR'"
    tudo_log 3 "TUDO_POST_SHELL_RCFILE_COMMANDS='$TUDO_POST_SHELL_RCFILE_COMMANDS'"
    tudo_log 3 "TUDO_POST_SHELL_RCFILE_VALUE=\`$TUDO_POST_SHELL_RCFILE_VALUE\`"

    return 0

}

##
# `tudo_set_shell_rcfile` `<shell_basename>` `<shell_home>` `<shell_share_rcfiles>`
##
tudo_set_shell_rcfile() {

    local return_value

    # If argument count is not 4
    if [ $# -ne 4 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_set_shell_rcfile'"
        return 1
    fi

    local shell_label="$1"
    local shell_basename="$2"
    local shell_home="$3"
    local shell_share_rcfiles="$4"

    # RCFILE are usually unique for different shells
    # If shell_home equals TERMUX_HOME, then termux shells and tudo shells
    # will share rc files by default unless shell_share_rcfiles is
    # enabled and the shell supports --rc param or an environment
    # variable.

    # Was going to add support for tcsh but decided not to after reading the following and having a chuckle
    # - https://web.fe.up.pt/~jmcruz/etc/unix/sh-vs-csh.html

    SHELL_RCFILE=""
    SHELL_RCFILE_PARENT_DIR=""
    SHELL_RCFILE_COMMANDS=""
    SHELL_RCFILE_VALUE=""
    SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=()

    # If shell is zsh
    if [[ "$shell_basename" == "zsh" ]]; then
        # If shell_home equals TERMUX_HOME, then termux shell and tudo shell rc files are shared
        # since only the parent dir of ".zshrc" file can be defined in ZDOTDIR
        SHELL_RCFILE="$shell_home/.zshrc"
        SHELL_RCFILE_COMMANDS="export ZDOTDIR='${shell_home//\'/\'\\\'\'}';"

    # If shell is fish
    elif [[ "$shell_basename" == "fish" ]]; then
        # If shell_home equals TERMUX_HOME, then termux shell and tudo shell rc files are shared since "config.fish" is always loaded
        SHELL_RCFILE="$shell_home/.config/fish/config.fish"
        SHELL_RCFILE_COMMANDS="export XDG_CONFIG_HOME='${shell_home//\'/\'\\\'\'}/.config';"
        SHELL_RCFILE_COMMANDS+=$'\n'"export XDG_CACHE_HOME='${shell_home//\'/\'\\\'\'}/.cache';"
        SHELL_RCFILE_COMMANDS+=$'\n'"export XDG_DATA_HOME='${shell_home//\'/\'\\\'\'}/.local/share';"
        SHELL_RCFILE_COMMANDS+=$'\n'"export XDG_RUNTIME_DIR='$TMPDIR';"
        SHELL_RCFILE_COMMANDS+=$'\n'"[ ! -d \"\$XDG_CONFIG_HOME\" ] && mkdir -p \"\$XDG_CONFIG_HOME\";"
        SHELL_RCFILE_COMMANDS+=$'\n'"[ ! -d \"\$XDG_CACHE_HOME\" ] && mkdir -p \"\$XDG_CACHE_HOME\";"
        SHELL_RCFILE_COMMANDS+=$'\n'"[ ! -d \"\$XDG_DATA_HOME\" ] && mkdir -p \"\$XDG_DATA_HOME\";"

    # If shell is ruby
    elif [[ "$shell_basename" == "ruby" ]]; then
        # If shell_home equals TERMUX_HOME, then termux shell and tudo shell rc files are shared since "~/.irbrc" is always loaded
        SHELL_RCFILE="$shell_home/.irbrc"

    # If shell is pry
    elif [[ "$shell_basename" == "pry" ]]; then
        # If shell_home equals TERMUX_HOME, then termux shell and tudo shell rc files are shared since "~/.pryrc" is always loaded
        SHELL_RCFILE="$shell_home/.pryrc"

    # If shell is bash, dash, sh, ksh, php, python
    elif [[ " bash dash sh ksh python php python2 " == *" $shell_basename "* ]]; then
        # If shell_home equals TERMUX_HOME and shell_share_rcfiles is not enabled, then set the RCFILE with "tudo_" appended to it
        # so that termux shell and tudo shell rc files are not shared since --rc params or
        # environment variables can be used to define the path to the rc file
        local shell_rcfile_subname
        if [[ "$shell_home" == "$TERMUX_HOME" ]] && [[ "$shell_share_rcfiles" != "1" ]]; then
            shell_rcfile_subname="tudo_${shell_basename}"
        else
            shell_rcfile_subname="${shell_basename}"
        fi

        # If shell is bash
        if [[ "$shell_basename" == "bash" ]]; then
            # Use the --rcfile param to pass the path to rcfile
            SHELL_RCFILE="$shell_home/.${shell_rcfile_subname}rc"
            SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS+=("--rcfile" "$SHELL_RCFILE")

        # If shell is python, python2
        elif [[ " python python2 " == *" $shell_basename "* ]]; then
            # Use the PYTHONSTARTUP environment variable to pass the path to rcfile
            SHELL_RCFILE="$shell_home/.${shell_rcfile_subname}rc"
            SHELL_RCFILE_COMMANDS="export PYTHONSTARTUP='${SHELL_RCFILE//\'/\'\\\'\'}';"

        # If shell is php
        elif [[ "$shell_basename" == "php" ]]; then
            # Use the -c param to pass the path to ini file
            SHELL_RCFILE="$shell_home/${shell_rcfile_subname}.ini"
            SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS+=("-c" "$SHELL_RCFILE")

        # If shell is dash, sh, ksh
        else
            # Use the PYTHONSTARTUP environment variable to pass the path to rcfile
            SHELL_RCFILE="$shell_home/.${shell_rcfile_subname}rc"
            SHELL_RCFILE_COMMANDS="export ENV='${SHELL_RCFILE//\'/\'\\\'\'}';"
        fi

    # If shell is node, perl, lua5.2, lua5.3, lua5.4
    elif [[ " node perl lua5.2 lua5.3 lua5.4 " == *" $shell_basename "* ]]; then
        # The shell does not have a rc file or does not use it
        tudo_log 3 "The '$shell_basename' shell does not have a rc file or does not use it"
    else
        tudo_log_errors "shell_basename '$shell_basename' not handled while running 'tudo_set_shell_rcfile'"
        return 1
    fi


    # If SHELL_RCFILE is set
    if [ -n "$SHELL_RCFILE" ]; then

        # If SHELL_RCFILE is not a valid absolute path
        if [[ ! "$SHELL_RCFILE" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
            tudo_log_errors "The ${shell_label}_RCFILE '$SHELL_RCFILE' is not a valid absolute path"
            return 1
        fi

        # If SHELL_RCFILE_COMMANDS is set
        if [ -n "$SHELL_RCFILE_COMMANDS" ]; then
            SHELL_RCFILE_COMMANDS+=$'\n'
        fi

        SHELL_RCFILE_COMMANDS+="export RCFILE='${SHELL_RCFILE//\'/\'\\\'\'}';"


        # Find the parent directory of the SHELL_RCFILE
        SHELL_RCFILE_BASENAME="${SHELL_RCFILE##*/}" # Strip longest match of */ from start
        SHELL_RCFILE_PARENT_DIR="${SHELL_RCFILE:0:${#SHELL_RCFILE} - ${#SHELL_RCFILE_BASENAME}}" # Substring from 0 to position of basename
        case "$SHELL_RCFILE_PARENT_DIR" in *[!/]*/) SHELL_RCFILE_PARENT_DIR="${SHELL_RCFILE_PARENT_DIR%"${SHELL_RCFILE_PARENT_DIR##*[!/]}"}";; *[/]) SHELL_RCFILE_PARENT_DIR="/";; esac # Remove trailing slashes if not root

        # Set SHELL_RCFILE_VALUE to be set in SHELL_RCFILE
        SHELL_RCFILE_VALUE=""

        # If shell is bash, zsh, dash, sh, fish or ksh
        if [[ " bash zsh dash sh fish ksh " == *" $shell_basename "* ]]; then
            # Not defining any variables since they are dynamically defined by "tudo" command
            # Overriding may create problems in the future as well if dynamically defined variable values change
            # PATH, LD_LIBRARY_PATH and PS1 must never be overridden in rcfile, otherwise "tudo" commands will not work properly,
            # especially the "tudo asu" and "tudo <command>" commands

            # Define any required functions to add to SHELL_RCFILE_VALUE in RCFILE_FUNCTIONS
            tudo_set_rcfile_functions "$shell_basename" || return $?

            # If RCFILE_FUNCTIONS is not empty, then append it to SHELL_RCFILE_VALUE
            if [ -n "$RCFILE_FUNCTIONS" ]; then
                SHELL_RCFILE_VALUE+="$RCFILE_FUNCTIONS"$'\n'
            fi
        fi
    fi

    return 0

}

##
# `tudo_set_rcfile_functions`
##
tudo_set_rcfile_functions() {

    local return_value

    # If argument count is not 1
    if [ $# -ne 1 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_set_rcfile_functions'"
        return 1
    fi

    local shell_basename="$1"

    RCFILE_FUNCTIONS=""

    # If shell is fish
    if [[ "$shell_basename" == "fish" ]]; then

        local fish_quiet_option=" -q"
        # If on Android `< 7`
        if [ "$ANDROID__BUILD_VERSION_SDK" -lt 24 ]; then
            fish_quiet_option=""
        fi

        # Define export helper function for fish shell that allows export command in bash to be used
        # shellcheck disable=SC2016
        FISH_SHELL_EXPORT_FUNCTION='
function export
    if [ $argv ]
        set var (echo $argv | cut -f1 -d=)
        set val (echo $argv | cut -f2 -d=)
        set -g -x $var $val
    end
end

'"funcsave$fish_quiet_option export
"

        # Define unset helper function for fish shell that allows export command in bash to be used
        # shellcheck disable=SC2016
        FISH_SHELL_UNSET_FUNCTION='
function unset
    set --erase $argv
end

'"funcsave$fish_quiet_option unset
"

    # Define tpath helper function for fish shell that sets priority to termux paths
    # shellcheck disable=SC2016
    FISH_SHELL_TPATH_FUNCTION='
function tpath
    export PATH="$TUDO__TERMUX_PRIORITY_PATH";
    export LD_LIBRARY_PATH="$TUDO__TERMUX_PRIORITY_LD_LIBRARY_PATH";
    export LD_PRELOAD="$TUDO__TERMUX_LD_PRELOAD";
end
'

    # Define apath helper function for fish shell that sets priority to android paths
    # shellcheck disable=SC2016
    FISH_SHELL_APATH_FUNCTION='
function apath
    export PATH="$TUDO__ANDROID_PRIORITY_PATH";
    export LD_LIBRARY_PATH="$TUDO__ANDROID_PRIORITY_LD_LIBRARY_PATH";
    '"$ANDROID_PRIORITY_LD_PRELOAD_COMMAND"'
end
'

        RCFILE_FUNCTIONS="$FISH_SHELL_EXPORT_FUNCTION"
        RCFILE_FUNCTIONS+=$'\n'"$FISH_SHELL_UNSET_FUNCTION"
        RCFILE_FUNCTIONS+=$'\n'"$FISH_SHELL_TPATH_FUNCTION"
        RCFILE_FUNCTIONS+=$'\n'"$FISH_SHELL_APATH_FUNCTION"





    # If shell is bash, zsh, dash, sh or ksh
    elif [[ " bash zsh dash sh ksh " == *" $shell_basename "* ]]; then

        # Define tpath helper function for bash, zsh, sh, etc shells that sets priority to termux paths
        # shellcheck disable=SC2016
        GENERAL_SHELL_TPATH_FUNCTION='
tpath() {
    export PATH="$TUDO__TERMUX_PRIORITY_PATH";
    export LD_LIBRARY_PATH="$TUDO__TERMUX_PRIORITY_LD_LIBRARY_PATH";
    export LD_PRELOAD="$TUDO__TERMUX_LD_PRELOAD";
}
'


        # Define apath helper function for bash, zsh, sh, etc shells that sets priority to android paths
        # shellcheck disable=SC2016
        GENERAL_SHELL_APATH_FUNCTION='
apath() {
    export PATH="$TUDO__ANDROID_PRIORITY_PATH";
    export LD_LIBRARY_PATH="$TUDO__ANDROID_PRIORITY_LD_LIBRARY_PATH";
    '"$ANDROID_PRIORITY_LD_PRELOAD_COMMAND"'
}
'


        RCFILE_FUNCTIONS="$GENERAL_SHELL_TPATH_FUNCTION"
        RCFILE_FUNCTIONS+=$'\n'"$GENERAL_SHELL_APATH_FUNCTION"

    fi

    return 0

}

tudo_set_tudo_shell_histfile() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_set_tudo_shell_histfile"

    # Set histfile variables
    tudo_set_shell_histfile "TUDO_SHELL" "$TUDO_SHELL_BASENAME" "$TUDO_SHELL_HOME" "$TUDO_SHELLS_HISTORY_ENABLED" "$TUDO_SHELL_SHARE_RCFILES_AND_HISTFILES"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failure while running 'tudo_set_shell_histfile' for TUDO_SHELL '$TUDO_SHELL'"
        return $return_value
    fi

    TUDO_SHELL_HISTFILE="$SHELL_HISTFILE"
    TUDO_SHELL_HISTFILE_PARENT_DIR="$SHELL_HISTFILE_PARENT_DIR"
    TUDO_SHELL_HISTFILE_COMMANDS="$SHELL_HISTFILE_COMMANDS"
    TUDO_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=("${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "${TUDO_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    tudo_log 3 "TUDO_SHELL_HISTFILE='$TUDO_SHELL_HISTFILE'"
    tudo_log 3 "TUDO_SHELL_HISTFILE_PARENT_DIR='$TUDO_SHELL_HISTFILE_PARENT_DIR'"
    tudo_log 3 "TUDO_SHELL_HISTFILE_COMMANDS='$TUDO_SHELL_HISTFILE_COMMANDS'"

    return 0

}

tudo_set_tudo_post_shell_histfile() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_set_tudo_post_shell_histfile"

    # Set histfile variables
    tudo_set_shell_histfile "TUDO_POST_SHELL" "$TUDO_POST_SHELL_BASENAME" "$TUDO_POST_SHELL_HOME" "$TUDO_SHELLS_HISTORY_ENABLED" "$TUDO_POST_SHELL_SHARE_RCFILES_AND_HISTFILES"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failure while running 'tudo_set_shell_histfile' for TUDO_POST_SHELL '$TUDO_POST_SHELL'"
        return $return_value
    fi

    TUDO_POST_SHELL_HISTFILE="$SHELL_HISTFILE"
    TUDO_POST_SHELL_HISTFILE_PARENT_DIR="$SHELL_HISTFILE_PARENT_DIR"
    TUDO_POST_SHELL_HISTFILE_COMMANDS="$SHELL_HISTFILE_COMMANDS"
    TUDO_POST_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=("${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "${TUDO_POST_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    tudo_log 3 "TUDO_POST_SHELL_HISTFILE='$TUDO_POST_SHELL_HISTFILE'"
    tudo_log 3 "TUDO_POST_SHELL_HISTFILE_PARENT_DIR='$TUDO_POST_SHELL_HISTFILE_PARENT_DIR'"
    tudo_log 3 "TUDO_POST_SHELL_HISTFILE_COMMANDS='$TUDO_POST_SHELL_HISTFILE_COMMANDS'"

    return 0

}

##
# `tudo_set_shell_histfile` `<shell_label>` `<shell_basename>` `<shell_home>` `<shell_history_enabled>` `<shell_share_histfiles>`
##
tudo_set_shell_histfile() {

    local return_value

    # If argument count is not 5
    if [ $# -ne 5 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_set_shell_histfile'"
        return 1
    fi

    local shell_label="$1"
    local shell_basename="$2"
    local shell_home="$3"
    local shell_history_enabled="$4"
    local shell_share_histfiles="$5"

    SHELL_HISTFILE=""
    SHELL_HISTFILE_PARENT_DIR=""
    SHELL_HISTFILE_COMMANDS=""
    SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=()

    # If shell_history_enabled is enabled
    if [[ "$shell_history_enabled" == "1" ]]; then

        # History files are usually unique for different shells
        # If shell_home equals TERMUX_HOME, then termux shells and tudo shells
        # will share history files by default unless
        # shell_share_histfiles is enabled and the shell supports
        # HISTFILE variable

        # If shell is fish
        if [[ "$shell_basename" == "fish" ]]; then
            local histfile_session_id

            # If shell_home and TERMUX_HOME are same and shell_share_histfiles is not enabled, then
            # set the HISTFILE with "tudo_" appended to it to keep tudo shells command history separate
            # from termux shells
            if [[ "$shell_home" == "$TERMUX_HOME" ]] && [[ "$shell_share_histfiles" != "1" ]]; then
                histfile_session_id="tudo_fish"
            else
                histfile_session_id="fish"
            fi

            # Fish uses the variable fish_history to store the session id for the history file
            # the history file ends up being "${fish_history}_history"
            SHELL_HISTFILE="$shell_home/.local/share/fish/${histfile_session_id}_history"
            SHELL_HISTFILE_COMMANDS="export fish_history='$histfile_session_id';"

        # If shell is python
        elif [[ "$shell_basename" == "python" ]]; then
            # python uses "~/.python_history" file to store history by default
            # History feature was introduced in 3.4
            SHELL_HISTFILE="$shell_home/.python_history"

        # If shell is ruby
        elif [[ "$shell_basename" == "ruby" ]]; then
            # irb uses "~/.irb_history" file to store history by default
            # If rvm is used, then its "~/.irb-history"
            # There are no params or environment variables that can be used to set history settings
            # History settings can be changed by defining following config options in "~/.irbrc" file
            # IRB.conf[:HISTORY_FILE] = "~/.irb_history"
            # IRB.conf[:SAVE_HISTORY] = 1000
            SHELL_HISTFILE="$shell_home/.irb_history"

        # If shell is pry
        elif [[ "$shell_basename" == "pry" ]]; then
            # pry uses "~/.pry_history" file to store history by default
            # There are no params or environment variables that can be used to set history settings
            # History settings can be changed by defining following config options in "~/.pryrc" file
            # Pry.config.history_file = "~/.pry_history"
            # Pry.config.history_load = true
            # Pry.config.history_save = true
            SHELL_HISTFILE="$shell_home/.pry_history"

        # If shell is php
        elif [[ "$shell_basename" == "php" ]]; then
            # php uses "~/.php_history" file to store history by default
            SHELL_HISTFILE="$shell_home/.php_history"

        # If shell is bash, zsh, dash, sh, ksh, node, perl
        elif [[ " bash zsh dash sh ksh node perl " == *" $shell_basename "* ]]; then
            # If shell_home and TERMUX_HOME are same and shell_share_histfiles is not enabled, then
            # set the HISTFILE with "tudo_" appended to it to keep tudo shells command history separate
            # from termux shells
            local shell_histfile_subname
            if [[ "$shell_home" == "$TERMUX_HOME" ]] && [[ "$shell_share_histfiles" != "1" ]]; then
                shell_histfile_subname="tudo_${shell_basename}"
            else
                shell_histfile_subname="${shell_basename}"
            fi

            # If shell is bash
            if [[ "$shell_basename" == "bash" ]]; then
                # Bash uses HISTFILE environment variable for history file
                SHELL_HISTFILE="$shell_home/.${shell_histfile_subname}_history"
                SHELL_HISTFILE_COMMANDS="export HISTSIZE=1000;"
                SHELL_HISTFILE_COMMANDS+=$'\n'"export HISTFILESIZE=1000;"
            # If shell is zsh
            elif [[ "$shell_basename" == "zsh" ]]; then
                # Zsh uses HISTFILE environment variable for history file
                SHELL_HISTFILE="$shell_home/.${shell_histfile_subname}_history"
                SHELL_HISTFILE_COMMANDS="export HISTSIZE=1000;"
                SHELL_HISTFILE_COMMANDS+=$'\n'"export SAVEHIST=1000;"

            # If shell is node
            elif [[ "$shell_basename" == "node" ]]; then
                # node uses NODE_REPL_HISTORY to define path for history file
                # and NODE_REPL_HISTORY_SIZE for size of history file
                SHELL_HISTFILE="$shell_home/.${shell_histfile_subname}_history"
                SHELL_HISTFILE_COMMANDS="export NODE_REPL_HISTORY='${SHELL_HISTFILE//\'/\'\\\'\'}';"
                SHELL_HISTFILE_COMMANDS+=$'\n'"export NODE_REPL_HISTORY_SIZE=1000;"

            # If shell is perl
            elif [[ "$shell_basename" == "perl" ]]; then
                # Use rlwrap "--history-filename" and "--histsize" params to set history settings
                SHELL_HISTFILE="$shell_home/.${shell_histfile_subname}_history"
                TUDO_RLWRAP_ADDITIONAL_COMMAND_OPTIONS+=("--history-filename" "$SHELL_HISTFILE" "--histsize" "1000")

            # If shell is dash sh ksh
            else
                # The shells use HISTFILE environment variable for history file
                SHELL_HISTFILE="$shell_home/.${shell_histfile_subname}_history"
            fi

        # If shell is python2, lua5.2, lua5.3, lua5.4
        elif [[ " python2 lua5.2 lua5.3 lua5.4 " == *" $shell_basename "* ]]; then
            # The shell does not have a history file or does not use it
            tudo_log 3 "The '$shell_basename' shell does not have a history file or does not use it"

        else
            tudo_log_errors "shell_basename '$shell_basename' not handled while running 'tudo_set_shell_histfile'"
            return 1
        fi


        # If SHELL_HISTFILE is set
        if [ -n "$SHELL_HISTFILE" ]; then
            # If SHELL_HISTFILE is not a valid absolute path
            if [[ ! "$SHELL_HISTFILE" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
                tudo_log_errors "The ${shell_label}_HISTFILE '$SHELL_HISTFILE' is not a valid absolute path"
                return 1
            fi

            # If SHELL_HISTFILE_COMMANDS is set
            if [ -n "$SHELL_HISTFILE_COMMANDS" ]; then
                SHELL_HISTFILE_COMMANDS+=$'\n'
            fi

            SHELL_HISTFILE_COMMANDS+="export HISTFILE='${SHELL_HISTFILE//\'/\'\\\'\'}';"

            # Find the parent directory of the SHELL_HISTFILE
            SHELL_HISTFILE_BASENAME="${SHELL_HISTFILE##*/}" # Strip longest match of */ from start
            SHELL_HISTFILE_PARENT_DIR="${SHELL_HISTFILE:0:${#SHELL_HISTFILE} - ${#SHELL_HISTFILE_BASENAME}}" # Substring from 0 to position of basename
            case "$SHELL_HISTFILE_PARENT_DIR" in *[!/]*/) SHELL_HISTFILE_PARENT_DIR="${SHELL_HISTFILE_PARENT_DIR%"${SHELL_HISTFILE_PARENT_DIR##*[!/]}"}";; *[/]) SHELL_HISTFILE_PARENT_DIR="/";; esac # Remove trailing slashes if not root
        fi

    else
        # If shell is fish
        if [[ "$shell_basename" == "fish" ]]; then
            # fish uses '--private' flag to disable history
            SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS+=("--private")

        # If shell is python
        elif [[ "$shell_basename" == "python" ]]; then
            # Disable the "readline.write_history_file" function that writes history to file
            SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS+=("-c" 'import readline; readline.write_history_file = lambda *args: None')

        # If shell is pry
        elif [[ "$shell_basename" == "pry" ]]; then
            # Use the "Pry.config.history_save" config to disable history saving
            # The "--no-history" flag to disable history loading is raising an exception in pry-0.13.1
            # Using the "Pry.config.history_load" config option with "-e" to disable history loading
            # does not work, since its already loaded by the time its run
            SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS+=("-e" 'Pry.config.history_save = false;')

        # If shell is node
        elif [[ "$shell_basename" == "node" ]]; then
            # node uses NODE_REPL_HISTORY to define path for history file
            # Unsetting it disables history
            SHELL_HISTFILE_COMMANDS="export NODE_REPL_HISTORY='';"

        # If shell is perl
        elif [[ "$shell_basename" == "perl" ]]; then
            # Use rlwrap "--history-filename" to set history settings
            TUDO_RLWRAP_ADDITIONAL_COMMAND_OPTIONS+=("--history-filename" "/dev/null")

        # If shell is bash, zsh, dash, sh, ksh
        elif [[ " bash zsh dash sh ksh " == *" $shell_basename "* ]]; then
            #if shell is bash
            #if [[ "$shell_basename" == "bash" ]]; then
                # bash uses 'history' shopt_option to control history, so unset it with a command option
                # for some reason this does not work since bash shell automatically enables history by default for interactive shells
                # can be confirmed by running "shopt -o" in a new interactive shell
                # SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS+=("+o" "history")
            #fi

            # Unsetting HISTFILE does not work for all shells like bash since it sets the default value if HISTFILE is not set
            # HISTFILE may still be overridden in a startup or a rc file
            SHELL_HISTFILE_COMMANDS="export HISTFILE='/dev/null';"

        # If shell is ruby, lua5.2, lua5.3, lua5.4, php, python2
        elif [[ " ruby lua5.2 lua5.3 lua5.4 php python2 " == *" $shell_basename "* ]]; then
            # The shell does not have a history file or does not use it or cannot be disabled using any params or environment variables
            tudo_log 3 "The '$shell_basename' shell does not have a history file or does not use it or cannot be disabled using any params or environment variables"

        else
            tudo_log_errors "shell_basename '$shell_basename' not handled while running 'tudo_set_shell_histfile'"
            return 1
        fi
    fi

    return 0

}

tudo_set_tudo_shell_command() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_set_tudo_shell_command"

    SHELL_ADDITIONAL_COMMAND_OPTIONS=("${TUDO_SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
    SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=("${TUDO_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    # Set shell command variables
    tudo_set_shell_command "TUDO_SHELL" "$TUDO_SHELL" "$TUDO_SHELL_BASENAME" "$TUDO_SHELL_PARENT_DIR" "$interactive_tudo_shell_required"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failure while running 'tudo_set_shell_command' for TUDO_SHELL '$TUDO_SHELL'"
        return $return_value
    fi

    TUDO_SHELL_COMMAND=("${SHELL_COMMAND[@]}")
    TUDO_SHELL_INTERACTIVE_COMMAND=("${SHELL_INTERACTIVE_COMMAND[@]}")
    TUDO_SHELL_COMMAND_PRINT_FORMAT="$SHELL_COMMAND_PRINT_FORMAT"
    TUDO_SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT="$SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT"


    tudo_log 3 "TUDO_SHELL_COMMAND='${TUDO_SHELL_COMMAND[*]}'"
    tudo_log 3 "TUDO_SHELL_INTERACTIVE_COMMAND='${TUDO_SHELL_INTERACTIVE_COMMAND[*]}'"

    return 0

}

tudo_set_tudo_post_shell_command() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_set_tudo_post_shell_command"

    SHELL_ADDITIONAL_COMMAND_OPTIONS=()
    SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS=("${TUDO_POST_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    # Set shell command variables
    tudo_set_shell_command "TUDO_POST_SHELL" "$TUDO_POST_SHELL" "$TUDO_POST_SHELL_BASENAME" "$TUDO_POST_SHELL_PARENT_DIR" 1
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failure while running 'tudo_set_shell_command' for TUDO_POST_SHELL '$TUDO_POST_SHELL'"
        return $return_value
    fi

    TUDO_POST_SHELL_INTERACTIVE_COMMAND=("${SHELL_INTERACTIVE_COMMAND[@]}")
    TUDO_POST_SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT="$SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT"

    tudo_log 3 "TUDO_POST_SHELL_INTERACTIVE_COMMAND='${TUDO_POST_SHELL_INTERACTIVE_COMMAND[*]}'"

    return 0

}

##
# `tudo_set_shell_command` `<shell_label>` `<shell>` `<shell_basename>` `<shell_parent_dir>` `<interactive_shell_required>`
##
tudo_set_shell_command() {

    local return_value

    # If argument count is not 5
    if [ $# -ne 5 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_set_shell_command'"
        return 1
    fi

    local shell_label="$1"
    local shell="$2"
    local shell_basename="$3"
    local shell_parent_dir="$4"
    local interactive_shell_required="$5"

    local shell_dependency_label=""
    local shell_dependency=""
    local shell_interactive_dependency_label=""
    local shell_interactive_dependency=""

    SHELL_COMMAND_PRINT_FORMAT="%q "
    SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT="%q "

    # If shell is bash
    if [[ "$shell_basename" == "bash" ]]; then
        SHELL_COMMAND=("$shell" "--noprofile" "--norc" "${SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
        SHELL_INTERACTIVE_COMMAND=("$shell" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "-i")

    # If shell is zsh
    elif [[ "$shell_basename" == "zsh" ]]; then
        SHELL_COMMAND=("$shell" "--no-rcs" "${SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
        SHELL_INTERACTIVE_COMMAND=("$shell" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "-i")

    # If shell is python, python2
    elif [[ " python python2 " == *" $shell_basename "* ]]; then
        SHELL_COMMAND=("$shell" "${SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
        SHELL_INTERACTIVE_COMMAND=("$shell" "-i" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    # If shell is ruby
    elif [[ "$shell_basename" == "ruby" ]]; then
        # The ruby interactive shell is named irb
        SHELL_COMMAND=("$shell" "${SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
        SHELL_INTERACTIVE_COMMAND=("$shell_parent_dir/irb" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

        shell_interactive_dependency_label="irb"
        shell_interactive_dependency="$TERMUX_BIN/irb"

    # If shell is pry
    elif [[ "$shell_basename" == "pry" ]]; then
        # pry does not support passing scripts, ruby must be used instead
        SHELL_COMMAND=()
        SHELL_INTERACTIVE_COMMAND=("$shell" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}")

    # If shell is perl
    elif [[ "$shell_basename" == "perl" ]]; then
        SHELL_COMMAND=("$shell" "${SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")

        # The perl interactive shell is started with rlwrap
        # rlwrap -A -pgreen -S "perl> " perl -wnE 'say eval()//$@'
        local shell_interactive_command_string;
        printf -v "shell_interactive_command_string" "%q " \
            "$TERMUX_BIN/rlwrap" "-A" "-pgreen" "-S" "perl> " "${TUDO_RLWRAP_ADDITIONAL_COMMAND_OPTIONS[@]}" \
                "$shell_parent_dir/perl" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "-wnE" 'say eval()//$@'
        SHELL_INTERACTIVE_COMMAND=("$shell_interactive_command_string")
        SHELL_INTERACTIVE_COMMAND_PRINT_FORMAT="%s"

        shell_interactive_dependency_label="rlwrap"
        shell_interactive_dependency="$TERMUX_BIN/rlwrap"

    # If shell is php
    elif [[ "$shell_basename" == "php" ]]; then
        SHELL_COMMAND=("$shell" "${SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
        SHELL_INTERACTIVE_COMMAND=("$shell" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "-a")

    # If shell is dash, sh, ksh, fish, node, lua5.2, lua5.3, lua5.4
        elif [[ " dash sh ksh fish node lua5.2 lua5.3 lua5.4 " == *" $shell_basename "* ]]; then
        SHELL_COMMAND=("$shell" "${SHELL_ADDITIONAL_COMMAND_OPTIONS[@]}")
        SHELL_INTERACTIVE_COMMAND=("$shell" "${SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS[@]}" "-i")
    else
        tudo_log_errors "shell_basename '$shell_basename' not handled while running 'tudo_set_shell_command'"
        return 1
    fi

    # If interactive_shell_required is not enabled
    if [[ "$interactive_shell_required" != "1" ]]; then
        # If shell_dependency is set
        if [ -n "$shell_dependency" ]; then
            tudo_run_file_type_tests_on_path "$shell_dependency_label" "$shell_dependency" 1 1 1 "frx"
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "'$shell_dependency_label' is required to run non-interactive '$shell_basename' shell"
                return $return_value
            fi
        fi
    else
        # If shell_interactive_dependency is set
        if [ -n "$shell_interactive_dependency" ]; then
            tudo_run_file_type_tests_on_path "$shell_interactive_dependency_label" "$shell_interactive_dependency" 1 1 1 "frx"
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "'$shell_interactive_dependency_label' is required to run interactive '$shell_basename' shell"
                return $return_value
            fi
        fi
    fi

    return 0

}

tudo_setup_tudo_shell_home_and_working_environment() {

    local return_value

    tudo_log_literal 3 "\n\n\nRunning tudo_setup_tudo_shell_home_and_working_environment"

    # tudo_setup_shell_home shell_label shell_home_parent_dir shell_home shell_automatically_create_rc_file shell_rcfile_parent_dir shell_rcfile shell_rcfile_value  shell_histfile_parent_dir shell_histfile
    tudo_setup_shell_home "TUDO_SHELL" "$TUDO_SHELL_HOME_PARENT_DIR" "$TUDO_SHELL_HOME" "$TUDO_SHELLS_AUTOMATICALLY_CREATE_RC_FILES" "$TUDO_SHELL_RCFILE_PARENT_DIR" "$TUDO_SHELL_RCFILE" "$TUDO_SHELL_RCFILE_VALUE" "$TUDO_SHELLS_AUTOMATICALLY_CREATE_HISTORY_FILES" "$TUDO_SHELL_HISTFILE_PARENT_DIR" "$TUDO_SHELL_HISTFILE"
    return_value=$?
    if [ $return_value -ne 0 ] && [ $return_value -ne 112 ]; then
        tudo_log_errors "Failed to setup TUDO_SHELL_HOME"
        return $return_value
    fi

    # If TUDO_POST_SHELL_HOME is set
    if [ -n "$TUDO_POST_SHELL_HOME" ]; then
        # If TUDO_SHELL and TUDO_POST_SHELL home, rcfile or histfiles are different
        if [[ "$TUDO_POST_SHELL_HOME" != "$TUDO_SHELL_HOME" ]] || \
                [[ "$TUDO_POST_SHELL_RCFILE" != "$TUDO_SHELL_RCFILE" ]] || \
                    [[ "$TUDO_POST_SHELL_HISTFILE" != "$TUDO_SHELL_HISTFILE" ]]; then
            # tudo_setup_shell_home shell_label shell_home_parent_dir shell_home shell_automatically_create_rc_file shell_rcfile_parent_dir shell_rcfile shell_rcfile_value shell_histfile_parent_dir  shell_histfile
            tudo_setup_shell_home "TUDO_POST_SHELL"  "$TUDO_POST_SHELL_HOME_PARENT_DIR" "$TUDO_POST_SHELL_HOME" "$TUDO_SHELLS_AUTOMATICALLY_CREATE_RC_FILES" "$TUDO_POST_SHELL_RCFILE_PARENT_DIR" "$TUDO_POST_SHELL_RCFILE" "$TUDO_POST_SHELL_RCFILE_VALUE" "$TUDO_SHELLS_AUTOMATICALLY_CREATE_HISTORY_FILES" "$TUDO_POST_SHELL_HISTFILE_PARENT_DIR" "$TUDO_POST_SHELL_HISTFILE"
            return_value=$?
            if [ $return_value -ne 0 ] && [ $return_value -ne 112 ]; then
                tudo_log_errors "Failed to setup TUDO_POST_SHELL_HOME"
                return $return_value
            fi
        fi
    fi

    # If TUDO_SHELL_WORKING_DIR is set and does not equal rootfs
    if [ -n "$TUDO_SHELL_WORKING_DIR" ] && [ "$TUDO_SHELL_WORKING_DIR" != "/" ]; then
        # Create TUDO_SHELL_WORKING_DIR if missing
        tudo_setup_tudo_shell_working_dir || return $?
    fi

    return 0

}

##
# `tudo_setup_shell_home` `<shell_label>` `<shell_home_parent_dir>` `<shell_home>` `<shell_automatically_create_rc_file>` `<shell_rcfile_parent_dir>` `<shell_rcfile>` `<shell_rcfile_value>`  `<shell_histfile_parent_dir>` `<shell_histfile>`
##
tudo_setup_shell_home() {

    local return_value

    # If argument count is not 10
    if [ $# -ne 10 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_setup_shell_home'"
        return 1
    fi

    local shell_label="$1"
    local shell_home_parent_dir="$2"
    local shell_home="$3"
    local shell_automatically_create_rc_file="$4"
    local shell_rcfile_parent_dir="$5"
    local shell_rcfile="$6"
    local shell_rcfile_value="$7"
    local shell_automatically_create_history_file="$8"
    local shell_histfile_parent_dir="$9"
    local shell_histfile="${10}"

    local create_shell_home_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_shell_home
    local shell_home_ownership
    local shell_home_permission
    local shell_home_file_type_tests

    local create_shell_rcfile_parent_dir_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_shell_rcfile_parent_dir
    local shell_rcfile_parent_dir_ownership
    local shell_rcfile_parent_dir_permission
    local shell_rcfile_parent_dir_file_type_tests

    local create_shell_rcfile_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_shell_rcfile
    local shell_rcfile_ownership
    local shell_rcfile_permission
    local shell_rcfile_file_type_tests

    local create_shell_histfile_parent_dir_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_shell_histfile_parent_dir
    local shell_histfile_parent_dir_ownership
    local shell_histfile_parent_dir_permission
    local shell_histfile_parent_dir_file_type_tests

    local create_shell_histfile_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_shell_histfile
    local shell_histfile_ownership
    local shell_histfile_permission
    local shell_histfile_file_type_tests

    local validation_result

    tudo_log_literal 3 "\nRunning tudo_setup_shell_home for $shell_label"



    create_shell_home_if_it_does_not_exist=1
    only_set_perms_and_ownership_on_creation_of_shell_home=1
    shell_home_permission="700"
    shell_home_file_type_tests="rwx"

    # Validate if shell_home is a whitelisted path under TERMUX_ROOTFS
    tudo_validate_path_is_a_whitelisted_path_under_termux_rootfs "${shell_label}_HOME" "$shell_home"
    return_value=$?
    if [ $return_value -ne 0 ] && [ $return_value -ne 2 ] &&  [ $return_value -ne 3 ]; then
        return $return_value
    fi

    validation_result=$return_value

    # If shell_home is a whitelisted path under TERMUX_ROOTFS
    if [ $validation_result -eq 0 ]; then
        shell_home_ownership="--reference=\"$TERMUX_ROOTFS\""
    # If shell_home is a blacklisted path under TERMUX_ROOTFS or is not under TERMUX_ROOTFS
    else
        tudo_log_errors "The '$shell_home' cannot be used as ${shell_label}_HOME"
        return 1
    fi



    # If shell_automatically_create_rc_file is not enabled or TUDO_DRY_RUN is enabled, then unset shell_rcfile
    if [[ "$shell_automatically_create_rc_file" != "1" ]] || [[ "$TUDO_DRY_RUN" == "1" ]]; then
        shell_rcfile=""
    fi

    # If shell_rcfile is set
    if [ -n "$shell_rcfile" ]; then
        # If shell_rcfile_parent_dir is not the same as shell_home or one of subdirectories
        if [[ "$shell_rcfile_parent_dir" != "$shell_home" ]] && [[ "$shell_rcfile_parent_dir" != "$shell_home"/* ]]; then
            tudo_log_errors "The ${shell_label}_RCFILE_PARENT_DIR '$shell_rcfile_parent_dir' must be same as ${shell_label}_HOME '$shell_home' or be one of its subdirectories"
            return 1
        fi

        create_shell_rcfile_parent_dir_if_it_does_not_exist=1
        only_set_perms_and_ownership_on_creation_of_shell_rcfile_parent_dir=1
        shell_rcfile_parent_dir_permission="700"
        shell_rcfile_parent_dir_file_type_tests="rwx"

        create_shell_rcfile_if_it_does_not_exist=1
        only_set_perms_and_ownership_on_creation_of_shell_rcfile=1
        shell_rcfile_permission="600"
        shell_rcfile_file_type_tests="rw"

        # Validate if shell_rcfile_parent_dir is a whitelisted path under TERMUX_ROOTFS
        tudo_validate_path_is_a_whitelisted_path_under_termux_rootfs "${shell_label}_RCFILE_PARENT_DIR" "$shell_rcfile_parent_dir"
            return_value=$?
        if [ $return_value -ne 0 ] && [ $return_value -ne 2 ] &&  [ $return_value -ne 3 ]; then
            return $return_value
        fi

        validation_result=$return_value

        # If shell_rcfile_parent_dir is a whitelisted path under TERMUX_ROOTFS
        if [ $validation_result -eq 0 ]; then
            shell_rcfile_parent_dir_ownership="--reference=\"$TERMUX_ROOTFS\""
            shell_rcfile_ownership="--reference=\"$TERMUX_ROOTFS\""
        # If shell_rcfile_parent_dir is a blacklisted path under TERMUX_ROOTFS or is not under TERMUX_ROOTFS
        else
            tudo_log_errors "The '$shell_rcfile_parent_dir' cannot be used as ${shell_label}_RCFILE_PARENT_DIR"
            return 1
        fi
    fi



    # If shell_automatically_create_history_files is not enabled or TUDO_DRY_RUN is enabled, then unset shell_histfile
    if [[ "$shell_automatically_create_history_file" != "1" ]] || [[ "$TUDO_DRY_RUN" == "1" ]]; then
        shell_histfile=""
    fi

    # If shell_histfile is set
    if [ -n "$shell_histfile" ]; then

        # If shell_histfile_parent_dir is not the same as shell_home or one of subdirectories
        if [[ "$shell_histfile_parent_dir" != "$shell_home" ]] && [[ "$shell_histfile_parent_dir" != "$shell_home"/* ]]; then
            tudo_log_errors "The ${shell_label}_HISTFILE_PARENT_DIR '$shell_histfile_parent_dir' must be same as ${shell_label}_HOME '$shell_home' or be one of its subdirectories"
            return 1
        fi

        create_shell_histfile_parent_dir_if_it_does_not_exist=1
        only_set_perms_and_ownership_on_creation_of_shell_histfile_parent_dir=1
        shell_histfile_parent_dir_permission="700"
        shell_histfile_parent_dir_file_type_tests="rwx"

        create_shell_histfile_if_it_does_not_exist=1
        only_set_perms_and_ownership_on_creation_of_shell_histfile=1
        shell_histfile_permission="600"
        shell_histfile_file_type_tests="rw"

        # Validate if shell_histfile_parent_dir is a whitelisted path under TERMUX_ROOTFS
        tudo_validate_path_is_a_whitelisted_path_under_termux_rootfs "${shell_label}_HISTFILE_PARENT_DIR" "$shell_histfile_parent_dir"
        return_value=$?
        if [ $return_value -ne 0 ] && [ $return_value -ne 2 ] &&  [ $return_value -ne 3 ]; then
            return $return_value
        fi

        validation_result=$return_value

        # If shell_histfile_parent_dir is a whitelisted path under TERMUX_ROOTFS
        if [ $validation_result -eq 0 ]; then
            shell_histfile_parent_dir_ownership="--reference=\"$TERMUX_ROOTFS\""
            shell_histfile_ownership="--reference=\"$TERMUX_ROOTFS\""
        # If shell_histfile_parent_dir is a blacklisted path under TERMUX_ROOTFS or is not under TERMUX_ROOTFS
        else
            tudo_log_errors "The '$shell_histfile_parent_dir' cannot be used as ${shell_label}_HISTFILE_PARENT_DIR"
            return 1
        fi
    fi



    tudo_create_shell_home "$shell_label" \
        "$shell_home" "$create_shell_home_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_home" "$shell_home_ownership" "$shell_home_permission" "$shell_home_file_type_tests" \
        "$shell_rcfile_parent_dir" "$create_shell_rcfile_parent_dir_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_rcfile_parent_dir" "$shell_rcfile_parent_dir_ownership" "$shell_rcfile_parent_dir_permission" "$shell_rcfile_parent_dir_file_type_tests" \
        "$shell_rcfile" "$create_shell_rcfile_if_it_does_not_exist" "$shell_rcfile_value" "$only_set_perms_and_ownership_on_creation_of_shell_rcfile" "$shell_rcfile_ownership" "$shell_rcfile_permission" "$shell_rcfile_file_type_tests" \
        "$shell_histfile_parent_dir" "$create_shell_histfile_parent_dir_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_histfile_parent_dir" "$shell_histfile_parent_dir_ownership" "$shell_histfile_parent_dir_permission" "$shell_histfile_parent_dir_file_type_tests" \
        "$shell_histfile" "$create_shell_histfile_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_histfile" "$shell_histfile_ownership" "$shell_histfile_permission" "$shell_histfile_file_type_tests"
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failure while running 'tudo_create_shell_home'"
        return $return_value
    fi

    return 0

}

##
# `tudo_create_shell_home` `<shell_label>` \
#     `<shell_home>` `<create_shell_home_if_it_does_not_exist>` `<only_set_perms_and_ownership_on_creation_of_shell_home>` `<shell_home_ownership>` `<shell_home_permission>` `<shell_home_file_type_tests>` \
#     `<shell_rcfile_parent_dir>` `<create_shell_rcfile_parent_dir_if_it_does_not_exist>` `<only_set_perms_and_ownership_on_creation_of_shell_rcfile_parent_dir>` `<shell_rcfile_parent_dir_ownership>` `<shell_rcfile_parent_dir_permission>` `<shell_rcfile_parent_dir_file_type_tests>` \
#     `<shell_rcfile>` `<create_shell_rcfile_if_it_does_not_exist>` `<shell_rcfile_value>` `<only_set_perms_and_ownership_on_creation_of_shell_rcfile>` `<shell_rcfile_ownership>` `<shell_rcfile_permission>` `<shell_rcfile_file_type_tests>` \
#     `<shell_histfile_parent_dir>` `<create_shell_histfile_parent_dir_if_it_does_not_exist>` `<only_set_perms_and_ownership_on_creation_of_shell_histfile_parent_dir>` `<shell_histfile_parent_dir_ownership>` `<shell_histfile_parent_dir_permission>` `<shell_histfile_parent_dir_file_type_tests>` \
#     `<shell_histfile>` `<create_shell_histfile_if_it_does_not_exist>` `<only_set_perms_and_ownership_on_creation_of_shell_histfile>` `<shell_histfile_ownership>` `<shell_histfile_permission>` `<shell_histfile_file_type_tests>`
##
tudo_create_shell_home() {

    local return_value

    # If argument count is not 32
    if [ $# -ne 32 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_create_shell_home'"
        return 1
    fi

    local shell_label="$1"

    local shell_home="$2"
    local create_shell_home_if_it_does_not_exist="$3"
    local only_set_perms_and_ownership_on_creation_of_shell_home="$4"
    local shell_home_ownership="$5"
    local shell_home_permission="$6"
    local shell_home_file_type_tests="$7"


    local shell_rcfile_parent_dir="$8"
    local create_shell_rcfile_parent_dir_if_it_does_not_exist="$9"
    local only_set_perms_and_ownership_on_creation_of_shell_rcfile_parent_dir="${10}"
    local shell_rcfile_parent_dir_ownership="${11}"
    local shell_rcfile_parent_dir_permission="${12}"
    local shell_rcfile_parent_dir_file_type_tests="${13}"


    local shell_rcfile="${14}"
    local create_shell_rcfile_if_it_does_not_exist="${15}"
    local shell_rcfile_value="${16}"
    local only_set_perms_and_ownership_on_creation_of_shell_rcfile="${17}"
    local shell_rcfile_ownership="${18}"
    local shell_rcfile_permission="${19}"
    local shell_rcfile_file_type_tests="${20}"


    local shell_histfile_parent_dir="${21}"
    local create_shell_histfile_parent_dir_if_it_does_not_exist="${22}"
    local only_set_perms_and_ownership_on_creation_of_shell_histfile_parent_dir="${23}"
    local shell_histfile_parent_dir_ownership="${24}"
    local shell_histfile_parent_dir_permission="${25}"
    local shell_histfile_parent_dir_file_type_tests="${26}"

    local shell_histfile="${27}"
    local create_shell_histfile_if_it_does_not_exist="${28}"
    local only_set_perms_and_ownership_on_creation_of_shell_histfile="${29}"
    local shell_histfile_ownership="${30}"
    local shell_histfile_permission="${31}"
    local shell_histfile_file_type_tests="${32}"



    # Create shell_home if missing and set ownership and permissions
    # tudo_create_modify_validate_directory directory_path_label directory_path check_if_absolute_path create_directory_if_it_does_not_exist only_set_perms_and_ownership_on_creation directory_chown_command_options directory_chmod_command_options sub_directories_chown_command_options sub_directories_chmod_command_options sub_files_chown_command_options sub_files_chmod_command_options file_type_tests
    tudo_create_modify_validate_directory "${shell_label}_HOME" "$shell_home" 1 "$create_shell_home_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_home" "$shell_home_ownership" "$shell_home_permission" - - - - "$shell_home_file_type_tests" || return $?



    # If shell_rcfile is set
    if [ -n "$shell_rcfile" ]; then
        # If shell_home and shell_rcfile_parent_dir are not same
        if [[ "$shell_home" != "$shell_rcfile_parent_dir" ]]; then
            # Create shell_rcfile_parent_dir if missing and set ownership and permissions
            # tudo_create_modify_validate_directory directory_path_label directory_path check_if_absolute_path create_directory_if_it_does_not_exist directory_chown_command_options directory_chmod_command_options sub_directories_chown_command_options sub_directories_chmod_command_options sub_files_chown_command_options sub_files_chmod_command_options file_type_tests
            tudo_create_modify_validate_directory "${shell_label}_RCFILE_PARENT_DIR" "$shell_rcfile_parent_dir" 1 "$create_shell_rcfile_parent_dir_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_rcfile_parent_dir" "$shell_rcfile_parent_dir_ownership" "$shell_rcfile_parent_dir_permission" - - - - "$shell_rcfile_parent_dir_file_type_tests" || return $?
        fi

        # Create shell_rcfile if missing and set ownership and permissions
        # tudo_create_modify_validate_file file_path_label file_path check_if_absolute_path create_file_if_it_does_not_exist file_creation_command_options file_content only_set_perms_and_ownership_on_creation file_chown_command_options file_chmod_command_options file_type_tests
        tudo_create_modify_validate_file "${shell_label}_RCFILE" "$shell_rcfile" 1 "$create_shell_rcfile_if_it_does_not_exist" "%s" "$shell_rcfile_value" "$only_set_perms_and_ownership_on_creation_of_shell_rcfile" "$shell_rcfile_ownership" "$shell_rcfile_permission" "$shell_rcfile_file_type_tests" || return $?
    fi



    # If shell_histfile is set
    if [ -n "$shell_histfile" ]; then
        # If shell_home and shell_histfile_parent_dir are not same
        # and shell_rcfile_parent_dir shell_histfile_parent_dir are not same
        if [[ "$shell_home" != "$shell_histfile_parent_dir" ]] && [[ "$shell_rcfile_parent_dir" != "$shell_histfile_parent_dir" ]]; then
            # Create shell_histfile_parent_dir if missing and set ownership and permissions
            # tudo_create_modify_validate_directory directory_path_label directory_path check_if_absolute_path create_directory_if_it_does_not_exist directory_chown_command_options directory_chmod_command_options sub_directories_chown_command_options sub_directories_chmod_command_options sub_files_chown_command_options sub_files_chmod_command_options file_type_tests
            tudo_create_modify_validate_directory "${shell_label}_HISTFILE_PARENT_DIR" "$shell_histfile_parent_dir" 1 "$create_shell_histfile_parent_dir_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_histfile_parent_dir" "$shell_histfile_parent_dir_ownership" "$shell_histfile_parent_dir_permission" - - - - "$shell_histfile_parent_dir_file_type_tests" || return $?
        fi

        # Create shell_histfile if missing and set ownership and permissions
        # tudo_create_modify_validate_file file_path_label file_path check_if_absolute_path create_file_if_it_does_not_exist file_creation_command_options file_content only_set_perms_and_ownership_on_creation file_chown_command_options file_chmod_command_options file_type_tests
        tudo_create_modify_validate_file "${shell_label}_HISTFILE" "$shell_histfile" 1 "$create_shell_histfile_if_it_does_not_exist" "%s" "" "$only_set_perms_and_ownership_on_creation_of_shell_histfile" "$shell_histfile_ownership" "$shell_histfile_permission" "$shell_histfile_file_type_tests" || return $?
    fi

    return 0

}

tudo_setup_termux_tmp_dir() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_setup_termux_tmp_dir"

    local create_termux_tmp_dir_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_termux_tmp_dir
    local termux_tmp_dir_permission
    local termux_tmp_dir_ownership
    local termux_tmp_dir_file_type_tests

    create_termux_tmp_dir_if_it_does_not_exist=1
    only_set_perms_and_ownership_on_creation_of_termux_tmp_dir=1
    termux_tmp_dir_ownership="--reference='$TERMUX_PREFIX'"
    termux_tmp_dir_permission="700"
    termux_tmp_dir_file_type_tests="drwx"


    # Create TMPDIR if missing
    # tudo_create_modify_validate_directory directory_path_label directory_path check_if_absolute_path create_directory_if_it_does_not_exist only_set_perms_and_ownership_on_creation directory_chown_command_options directory_chmod_command_options sub_directories_chown_command_options sub_directories_chmod_command_options sub_files_chown_command_options sub_files_chmod_command_options file_type_tests
    tudo_create_modify_validate_directory "TMPDIR" "$TMPDIR" 1 "$create_termux_tmp_dir_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_termux_tmp_dir" "$termux_tmp_dir_ownership" "$termux_tmp_dir_permission" - - - - "$termux_tmp_dir_file_type_tests" || return $?

    return 0

}

tudo_set_tudo_shell_working_dir() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_set_tudo_shell_working_dir"

    if [ "$TUDO_SHELL_WORKING_DIR" != "/" ]; then
        # Replace "$PREFIX/" or "~/" prefix with termux absolute paths in TUDO_SHELL_WORKING_DIR
        tudo_expand_termux_path "TUDO_SHELL_WORKING_DIR" "TUDO_SHELL_WORKING_DIR" "$TUDO_SHELL_WORKING_DIR" "$TERMUX_PREFIX" "$TERMUX_HOME" 1
        return_value=$?
        if [ $return_value -ne 0 ]; then
            tudo_log_errors "Failed to expand TUDO_SHELL_WORKING_DIR '$TUDO_SHELL_WORKING_DIR'"
            return $return_value
        fi
    fi

    # If TUDO_SHELL_WORKING_DIR is not a valid absolute path
    if [[ ! "$TUDO_SHELL_WORKING_DIR" =~ $VALID_ROOTFS_OR_ABSOLUTE_PATH_REGEX ]]; then
        tudo_log_errors "The TUDO_SHELL_WORKING_DIR '$TUDO_SHELL_WORKING_DIR' is not a valid absolute path"
        return 1
    fi

    tudo_log 2 "TUDO_SHELL_WORKING_DIR='$TUDO_SHELL_WORKING_DIR'"

    # Find the parent directory of the TUDO_SHELL_WORKING_DIR
    TUDO_SHELL_WORKING_DIR_BASENAME="${TUDO_SHELL_WORKING_DIR##*/}" # Strip longest match of */ from start
    TUDO_SHELL_WORKING_DIR_PARENT_DIR="${TUDO_SHELL_WORKING_DIR:0:${#TUDO_SHELL_WORKING_DIR} - ${#TUDO_SHELL_WORKING_DIR_BASENAME}}" # Substring from 0 to position of basename
    case "$TUDO_SHELL_WORKING_DIR_PARENT_DIR" in *[!/]*/) TUDO_SHELL_WORKING_DIR_PARENT_DIR="${TUDO_SHELL_WORKING_DIR_PARENT_DIR%"${TUDO_SHELL_WORKING_DIR_PARENT_DIR##*[!/]}"}";; *[/]) TUDO_SHELL_WORKING_DIR_PARENT_DIR="/";; esac # Remove trailing slashes if not root

    tudo_log 3 "TUDO_SHELL_WORKING_DIR_PARENT_DIR='$TUDO_SHELL_WORKING_DIR_PARENT_DIR'"

    return 0

}

tudo_setup_tudo_shell_working_dir() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_setup_tudo_shell_working_dir"

    local create_shell_working_dir_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_shell_working_dir
    local shell_working_dir_permission
    local shell_working_dir_ownership
    local shell_working_dir_file_type_tests

    create_shell_working_dir_if_it_does_not_exist=1
    only_set_perms_and_ownership_on_creation_of_shell_working_dir=1
    shell_working_dir_permission="700"

    # Find the parent directory of the TUDO_SHELL_WORKING_DIR
    TUDO_SHELL_WORKING_DIR_BASENAME="${TUDO_SHELL_WORKING_DIR##*/}" # Strip longest match of */ from start
    TUDO_SHELL_WORKING_DIR_PARENT_DIR="${TUDO_SHELL_WORKING_DIR:0:${#TUDO_SHELL_WORKING_DIR} - ${#TUDO_SHELL_WORKING_DIR_BASENAME}}" # Substring from 0 to position of basename
    case "$TUDO_SHELL_WORKING_DIR_PARENT_DIR" in *[!/]*/) TUDO_SHELL_WORKING_DIR_PARENT_DIR="${TUDO_SHELL_WORKING_DIR_PARENT_DIR%"${TUDO_SHELL_WORKING_DIR_PARENT_DIR##*[!/]}"}";; *[/]) TUDO_SHELL_WORKING_DIR_PARENT_DIR="/";; esac # Remove trailing slashes if not root

    shell_working_dir_ownership="--reference='${TUDO_SHELL_WORKING_DIR_PARENT_DIR//\'/\'\\\'\'}'"


    # If TUDO_SHELL_WORKING_DIR is the same as TERMUX_ROOTFS or is under it
    if [[ "$TUDO_SHELL_WORKING_DIR" == "$TERMUX_ROOTFS" ]] || [[ "$TUDO_SHELL_WORKING_DIR" == "$TERMUX_ROOTFS"/* ]]; then
        shell_working_dir_file_type_tests="drwx"
    # It might not be possible for the directory to be writable or executable in other paths like in storage or rootfs/system partition
    else
        shell_working_dir_file_type_tests="dr"
    fi


    # Create TUDO_SHELL_WORKING_DIR if missing
    # tudo_create_modify_validate_directory directory_path_label directory_path check_if_absolute_path create_directory_if_it_does_not_exist only_set_perms_and_ownership_on_creation directory_chown_command_options directory_chmod_command_options sub_directories_chown_command_options sub_directories_chmod_command_options sub_files_chown_command_options sub_files_chmod_command_options file_type_tests
    tudo_create_modify_validate_directory "TUDO_SHELL_WORKING_DIR" "$TUDO_SHELL_WORKING_DIR" 1 "$create_shell_working_dir_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_working_dir" "$shell_working_dir_ownership" "$shell_working_dir_permission" - - - - "$shell_working_dir_file_type_tests" || return $?

    return 0

}

tudo_set_tudo_temp_directory_parent_directory() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_set_tudo_temp_directory_parent_directory"

    # Use TMPDIR as TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY
    TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY="$TMPDIR"

    # If TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY is not a valid absolute path
    if [[ ! "$TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        tudo_log_errors "The TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY '$TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY' is not a valid absolute path"
        return 1
    fi

    # If TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY is not set to an absolute path under TERMUX_ROOTFS
    if [[ ! "$TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY" =~ $VALID_PATH_UNDER_TERMUX_ROOTFS_REGEX ]]; then
        tudo_log_errors "The TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY '$TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY' must be an absolute path under TERMUX_ROOTFS '$TERMUX_ROOTFS'"
    fi

    # If TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY is an absolute path under TERMUX_HOME
    if [[ "$TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY" =~ $VALID_PATH_UNDER_TERMUX_HOME_REGEX ]]; then
        tudo_log_errors "The TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY '$TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY' must not be an absolute path under TERMUX_HOME '$TERMUX_HOME'"
    fi

    # If REMOVE_PREVIOUS_TUDO_TEMP_FILES is enabled
    if [[ "$REMOVE_PREVIOUS_TUDO_TEMP_FILES" == "1" ]]; then
        # If TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY is set to an absolute path and TUDO_TEMP_DIRECTORY_PREFIX is not empty
        if [[ "$TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY" =~ $VALID_ABSOLUTE_PATH_REGEX ]] && [ -n "$TUDO_TEMP_DIRECTORY_PREFIX" ]; then
            # Remove all directories with the prefix TUDO_TEMP_DIRECTORY_PREFIX
            tudo_log_literal 3 "\nRemove all directories with the prefix '$TUDO_TEMP_DIRECTORY_PREFIX' in TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY '$TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY'"
            find "$TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY" -maxdepth 1 -type d -name "$TUDO_TEMP_DIRECTORY_PREFIX*" -exec rm -rf "{}" \;
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "Failure while removing all directories with the prefix '$TUDO_TEMP_DIRECTORY_PREFIX' in TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY '$TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY'"
                return $return_value
            fi
        fi
    fi

    #tudo_log 3 "TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY='$TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY'"

    return 0

}

tudo_setup_tudo_temp_directory() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_setup_tudo_temp_directory"

    local create_shell_tudo_temp_dir_parent_dir_if_it_does_not_exist
    local only_set_perms_and_ownership_on_creation_of_shell_tudo_temp_dir_parent_dir
    local shell_tudo_temp_dir_parent_dir_permission
    local shell_tudo_temp_dir_parent_dir_ownership
    local shell_tudo_temp_dir_parent_dir_file_type_tests

    create_shell_tudo_temp_dir_parent_dir_if_it_does_not_exist=1
    only_set_perms_and_ownership_on_creation_of_shell_tudo_temp_dir_parent_dir=1
    shell_tudo_temp_dir_parent_dir_ownership="--reference=\"$TERMUX_ROOTFS\""
    shell_tudo_temp_dir_parent_dir_permission="700"
    shell_tudo_temp_dir_parent_dir_file_type_tests="drwx"

    # Create TUDO_SHELL_WORKING_DIR if missing
    # tudo_create_modify_validate_directory directory_path_label directory_path check_if_absolute_path create_directory_if_it_does_not_exist only_set_perms_and_ownership_on_creation directory_chown_command_options directory_chmod_command_options sub_directories_chown_command_options sub_directories_chmod_command_options sub_files_chown_command_options sub_files_chmod_command_options file_type_tests
    tudo_create_modify_validate_directory "TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY" "$TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY" 1 "$create_shell_tudo_temp_dir_parent_dir_if_it_does_not_exist" "$only_set_perms_and_ownership_on_creation_of_shell_tudo_temp_dir_parent_dir" "$shell_tudo_temp_dir_parent_dir_ownership" "$shell_tudo_temp_dir_parent_dir_permission" - - - - "$shell_tudo_temp_dir_parent_dir_file_type_tests" || return $?


    # Create a temp directory in TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY to store temp scripts used by the tudo script
    # TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY by default would be same as TMPDIR
    # TMPDIR is used since obv thats what its for, duh!
    # Moreover termux will automatically remove the temp directory when its sessions are closed if it was not
    # automatically removed at the end of tudo execution and left there
    # The temp directory must be under TERMUX_ROOTFS so that it can be created by the 'Termux app' user
    # The temp directory must not be under TERMUX_HOME since other apps with SAF access can access it
    # A directory is created to store script files since if '--script-name' is passed, then there may
    # be conflicts between executions since temp files will share the same parent directory and have the same name
    # This will allow each execution of the script to have a separate directory for itself with a random suffix
    # Scripts will also have an empty directory to use that will be unique for them, which will be removed after execution
    TUDO_TEMP_DIRECTORY="$(mktemp -d --tmpdir="$TUDO_TEMP_DIRECTORY_PARENT_DIRECTORY" "$TUDO_TEMP_DIRECTORY_PREFIX.XXXXXX")"
    return_value=$?
    if [ $return_value -ne 0 ] || [[ ! "$TUDO_TEMP_DIRECTORY" =~ $VALID_ABSOLUTE_PATH_REGEX ]]; then
        tudo_log_errors "Failure while running mktemp to create TUDO_TEMP_DIRECTORY"
        tudo_log_errors "TUDO_TEMP_DIRECTORY='$TUDO_TEMP_DIRECTORY'"
        if [ $return_value -eq 0 ]; then
            return_value=1
        fi
        return $return_value
    fi

    return 0

}

set_tudo_traps() {

    local trap_function="${1:-}"

    if [[ ! "$trap_function" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then
        tudo_log_errors "The trap_function '$trap_function' argument passed to \
'set_tudo_traps' is not a valid function name."
        return 64 # EX__USAGE
    fi

    # shellcheck disable=SC2064
    trap "$trap_function" EXIT
    # shellcheck disable=SC2064
    trap "$trap_function TERM" TERM
    # shellcheck disable=SC2064
    trap "$trap_function INT" INT
    # shellcheck disable=SC2064
    trap "$trap_function HUP" HUP
    # shellcheck disable=SC2064
    trap "$trap_function QUIT" QUIT

    return 0

}

tudo_trap() {

    # The tudo_trap will do the following:
    # Store the original trap signal in $tudo_exit_code.
    # Remove the EXIT trap so its not called again.
    # Remove temp_directory if set if tudo command failed.
    # If a signal argument was passed, then remove its trap and
    # then exit with the original trap signal exit code
    # so that parent processes can be notified if necessary.

    local tudo_exit_code=$?
    trap - EXIT

    [ $tudo_exit_code -ne 0 ] && tudo_remove_tudo_temp_directory

    [ -n "${1:-}" ] && trap - "$1"
    exit $tudo_exit_code

}

tudo_remove_tudo_temp_directory() {

    # If TUDO_TEMP_DIRECTORY is a valid absolute path and
    # DO_NOT_DELETE_TUDO_TEMP_DIRECTORY_ON_EXIT is not enabled
    if [[ "$TUDO_TEMP_DIRECTORY" =~ $VALID_ABSOLUTE_PATH_REGEX ]] && \
        [[ "$DO_NOT_DELETE_TUDO_TEMP_DIRECTORY_ON_EXIT" != "1" ]]; then
        # Remove TUDO_TEMP_DIRECTORY in case it wasn't already removed
        tudo_log_literal 3 "\nRemoving TUDO_TEMP_DIRECTORY in case it wasn't already removed"
        rm -rf "$TUDO_TEMP_DIRECTORY"
        TUDO_TEMP_DIRECTORY=""
    fi

}

tudo_create_script_command_traps() {

    local return_value

    tudo_log_literal 3 "\nRunning tudo_create_script_command_traps"

    # The tudo_script__trap will do the following:
    # Store the original trap signal in $tudo_script__exit_code.
    # Call the tudo_script__custom_trap function.
    # If it exits with 0, then continue normally.
    # If it exits with 125 'ECANCELED', then do not continue and just return.
    # If it exits with any other exit code, store it so that we exit
    # with that instead of the original trap signal.
    # Remove the EXIT trap so its not called again.
    # Remove temp_directory if set.
    # If a signal argument was passed, then remove its trap.
    # Send the original trap signal to all the children of the pid
    # and exit with the original trap signal exit code or that of the
    # tudo_script__custom_trap function so that parent processes can be
    # notified if necessary.

    TUDO_SCRIPT_COMMAND_TRAPS=""

    # If TUDO_TEMP_DIRECTORY is a valid absolute path and DO_NOT_DELETE_TUDO_TEMP_DIRECTORY_ON_EXIT is not enabled
    if [[ "$TUDO_TEMP_DIRECTORY" =~ $VALID_ABSOLUTE_PATH_REGEX ]] && [[ "$DO_NOT_DELETE_TUDO_TEMP_DIRECTORY_ON_EXIT" != "1" ]]; then
        # Append the function to TUDO_SCRIPT_COMMAND_TRAPS to remove TUDO_TEMP_DIRECTORY
        # This may specially be necessary if '-E' is passed
        TUDO_SCRIPT_COMMAND_TRAPS_REMOVE_TEMP_DIRECTORY_FUNCTION="tudo_script__remove_temp_directory"

        TUDO_SCRIPT_COMMAND_TRAPS+='
export TUDO_SCRIPT__TEMP_DIR='"'${TUDO_TEMP_DIRECTORY//\'/\'\\\'\'}'"'

'"$TUDO_SCRIPT_COMMAND_TRAPS_REMOVE_TEMP_DIRECTORY_FUNCTION"'() {
    rm -rf '"'${TUDO_TEMP_DIRECTORY//\'/\'\\\'\'}'"'
}
'
    else
        TUDO_SCRIPT_COMMAND_TRAPS_REMOVE_TEMP_DIRECTORY_FUNCTION=""
    fi

    # FIXME: Use alternate for `pgrep` as it will not be available on
    # Android `< 6` if PATH is set to `/system/bin`. Termux does
    # provide it with `procps` package under `$TERMUX_PREFIX/bin`.
    # shellcheck disable=SC2016
    local tudo_script__killtree_command='tudo_script__killtree "${1:-}" $$'
    # If on Android `< 6`
    if [ "$ANDROID__BUILD_VERSION_SDK" -lt 23 ]; then
        tudo_script__killtree_command='command -v "pgrep" 1>/dev/null 2>&1 && '"$tudo_script__killtree_command"
    fi

    # shellcheck disable=SC2016
    TUDO_SCRIPT_COMMAND_TRAPS+='
tudo_script__custom_trap() { :; }

tudo_script__killtree() {
    local signal="$1"; local pid="$2"; local cpid
    for cpid in $(pgrep -P "$pid"); do tudo_script__killtree "$signal" "$cpid"; done
    [ "$pid" != "$$" ] && kill "-${signal:-15}" "$pid" 2>/dev/null
}

tudo_script__trap() {
    local tudo_script__exit_code=$?
    local return_value=0; tudo_script__custom_trap "$@" || return_value=$?
    [ $return_value -eq 125 ] && return 0
    [ $return_value -ne 0 ] && tudo_script__exit_code=$return_value
    trap - EXIT '"${TUDO_SCRIPT_COMMAND_TRAPS_REMOVE_TEMP_DIRECTORY_FUNCTION:+$'\n'    $TUDO_SCRIPT_COMMAND_TRAPS_REMOVE_TEMP_DIRECTORY_FUNCTION}"'
    [ -n "${1:-}" ] && trap - "$1"
    '"$tudo_script__killtree_command"'; exit $tudo_script__exit_code
}
'"
trap 'tudo_script__trap' EXIT
trap 'tudo_script__trap TERM' TERM
trap 'tudo_script__trap INT' INT
trap 'tudo_script__trap HUP' HUP
trap 'tudo_script__trap QUIT' QUIT
"
    return 0

}

##
# `tudo_run_file_type_tests_on_path` `<label>` `<path>` `<log_file_tests_failure_errors>` `<show_stat_output_on_file_tests_failure>` `<check_if_absolute_path>` `<file_type_tests>`
##
tudo_run_file_type_tests_on_path() {

    local return_value

    # If argument count is not 6
    if [ $# -ne 6 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_run_file_type_tests_on_path'"
        return 1
    fi

    local label="$1"
    local path="$2"
    local log_file_tests_failure_errors="$3"
    local show_stat_output_on_file_tests_failure="$4"
    local check_if_absolute_path="$5"
    local file_type_tests="$6"

    # If file_type_tests is invalid
    if [[ ! "$file_type_tests" =~ ^[bcdefgGkhLOprSsuwx]+$ ]]; then
        tudo_log_errors "file_type_tests '$file_type_tests' passed to 'tudo_run_file_type_tests_on_path' is not valid"
        return 1
    fi

    # If check_if_absolute_path is enabled and path is not a valid absolute path
    local valid_rootfs_or_absolute_path_regex='^((/)|((/[^/]+)+))$'
    if [[ "$check_if_absolute_path" == "1" ]] && [[ ! "$path" =~ $valid_rootfs_or_absolute_path_regex ]]; then
        tudo_log_errors "The '$label' file '$path' is not an absolute path"
        return 2
    fi

    local command=""

    for (( i=0; i<${#file_type_tests}; i++ )); do
        file_type_test="${file_type_tests:$i:1}"

        [[ -n "$command" ]] && command+=" && "
        command+="test -$file_type_test '${path//\'/\'\\\'\'}'" # Replace any single quotes `'` with `'\''` to maintain quoting and prevent arbitrary command execution with eval
    done

    # If command is empty
    if [[ -z "$command" ]]; then
        return 0
    fi

    # Run all tests
    # 0 means success, 1 means failure, other exit codes mean some other error
    eval "$command"
    return_value=$?
    if [ $return_value -eq 0 ]; then
        return 0
    fi

    if [ $return_value -ne 1 ] || \
        { [ $return_value -eq 1 ] && [[ "$log_file_tests_failure_errors" == "1" ]]; }; then
        local file_type_tests_label=""

        declare -A file_type_tests_labels=(
            ["b"]="[block special device]"
            ["c"]="[character special device]"
            ["d"]="[directory]"
            ["e"]="[exists]"
            ["f"]="[regular file]"
            ["g"]="[set-group-id bit set]"
            ["G"]="[owned by the current effective group id]"
            ["k"]="[sticky bit set]"
            ["h"]="[symbolic link]"
            ["L"]="[symbolic link]"
            ["O"]="[owned by the current effective user id]"
            ["p"]="[pipe]"
            ["r"]="[readable]"
            ["S"]="[socket]"
            ["s"]="[size greater than zero]"
            ["u"]="[set-user-id bit set]"
            ["w"]="[writable]"
            ["x"]="[executable]"
        )

        for (( i=0; i<${#file_type_tests}; i++ )); do
            file_type_test="${file_type_tests:$i:1}"

            [[ -n "$file_type_tests_label" ]] && file_type_tests_label+=", "
            file_type_tests_label+="${file_type_tests_labels[$file_type_test]}"
        done
    fi

    if [ $return_value -ne 1 ]; then
        tudo_log_errors "Failed to run the following test types on the file '$label' at path '$path': $file_type_tests_label"
    else
        if [[ "$log_file_tests_failure_errors" == "1" ]]; then
            tudo_log_errors "The '$label' file at path '$path' failed one or more of the following test types: $file_type_tests_label"
            if [[ "$show_stat_output_on_file_tests_failure" == "1" ]]; then
                current_user_id="$(id -u 2>/dev/null)"
                current_user_name="$(id -un 2>/dev/null)"
                stat_output="$(stat --format="file type: %F"$'\n'"access: %A (%a)"$'\n'"owner: %U (%u)"$'\n'"group: %G (%g)"$'\n'"selinux context: %C"$'\n'"size: %s" "$path" 2>/dev/null)"
                # If stat_output is not empty
                if [[ -n "$stat_output" ]]; then
                    tudo_log_errors "current user: $current_user_name ($current_user_id)"$'\n'"$stat_output"
                fi
            fi
        fi
    fi

    return $return_value

}

##
# `tudo_create_modify_validate_directory` `<directory_path_label>` `<directory_path>` `<check_if_absolute_path>` `<create_directory_if_it_does_not_exist>` `<only_set_perms_and_ownership_on_creation>` `<directory_chown_command_options>` `<directory_chmod_command_options>` `<sub_directories_chown_command_options>` `<sub_directories_chmod_command_options>` `<sub_files_chown_command_options>` `<sub_files_chmod_command_options>` `<file_type_tests>`
##
tudo_create_modify_validate_directory() {

    local return_value

    # If argument count is not 12
    if [ $# -ne 12 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_create_modify_validate_directory'"
        return 1
    fi

    #tudo_log_literal 3 "\nRunning tudo_create_modify_validate_directory"

    local directory_path_label="$1"
    local directory_path="$2"
    local check_if_absolute_path="$3"
    local create_directory_if_it_does_not_exist="$4"
    local only_set_perms_and_ownership_on_creation="$5"
    local directory_chown_command_options="$6"
    local directory_chmod_command_options="$7"
    local sub_directories_chown_command_options="$8"
    local sub_directories_chmod_command_options="$9"
    local sub_files_chown_command_options="${10}"
    local sub_files_chmod_command_options="${11}"
    local file_type_tests="${12}"

    local directory_created=0

    # If create_directory_if_it_does_not_exist is not set to 0 or 1
    if [[ "$create_directory_if_it_does_not_exist" != "0" ]] && [[ "$create_directory_if_it_does_not_exist" != "1" ]]; then
        tudo_log_errors "create_directory_if_it_does_not_exist '$create_directory_if_it_does_not_exist' passed to 'tudo_create_modify_validate_directory' is not equal to '0' or '1'"
        return 1
    fi

    # If only_set_perms_and_ownership_on_creation is not set to 0 or 1
    if [[ "$only_set_perms_and_ownership_on_creation" != "0" ]] && [[ "$only_set_perms_and_ownership_on_creation" != "1" ]]; then
        tudo_log_errors "only_set_perms_and_ownership_on_creation '$only_set_perms_and_ownership_on_creation' passed to 'tudo_create_modify_validate_directory' is not equal to '0' or '1'"
        return 1
    fi

    # If check_if_absolute_path is enabled and directory_path is not a valid absolute path
    local valid_rootfs_or_absolute_path_regex='^((/)|((/[^/]+)+))$'
    if [[ "$check_if_absolute_path" == "1" ]] && [[ ! "$directory_path" =~ $valid_rootfs_or_absolute_path_regex ]]; then
        tudo_log_errors "The '$directory_path_label' directory '$directory_path' is not an absolute path"
        return 2
    fi

    # Check if a non-directory file exists at directory path
    if [ -e "$directory_path" ] && [ ! -d "$directory_path" ]; then
        tudo_log_errors "A non-directory file exists at $directory_path_label '$directory_path'"
        return 1
    fi

    # If directory does not exist
    if [ ! -d "$directory_path" ]; then
        # If create_directory_if_it_does_not_exist is enabled, then create directory
        if [[ "$create_directory_if_it_does_not_exist" == "1" ]]; then
            tudo_log 3 "Creating $directory_path_label directory at '$directory_path'"

            mkdir -p "$directory_path"
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "Failed to create $directory_path_label directory at '$directory_path'"
                return $return_value
            fi

            if [ ! -d "$directory_path" ]; then
                tudo_log_errors "Failed to find $directory_path_label directory at '$directory_path' after creation"
                return 1
            fi

            directory_created=1
        else
            tudo_log_errors "Failed to find $directory_path_label directory at '$directory_path'"
            return 1
        fi
    else
        if [[ "$create_directory_if_it_does_not_exist" == "1" ]]; then
            tudo_log 3 "The $directory_path_label directory already exists at '$directory_path'"
        else
            tudo_log 3 "The $directory_path_label directory exists at '$directory_path'"
        fi
    fi

    # If only_set_perms_and_ownership_on_creation is enabled and directory was not created
    if  [[ "$only_set_perms_and_ownership_on_creation" == "1" ]] && [[ "$directory_created" == "0" ]]; then
        tudo_log 3 "Skipping setting ownership and permission for $directory_path_label directory since it was not created"
    else

        # Set directory ownership
        if [[ "$directory_chown_command_options" != "-" ]]; then
            local -a directory_chown_command_options_array=()
            tudo_set_shell_command_args_array directory_chown_command_options_array \
                "directory_chown_command_options" "$directory_chown_command_options" || return $?

            tudo_log 3 "Setting '${directory_chown_command_options_array[*]}' ownership to $directory_path_label directory at '$directory_path' directory"
            chown "${directory_chown_command_options_array[@]}" "$directory_path"
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "Failed to set ownership of $directory_path_label directory at '$directory_path'"
                return $return_value
            fi
        fi

        # Set directory permissions
        if [[ "$directory_chmod_command_options" != "-" ]]; then
            local -a directory_chmod_command_options_array=()
            tudo_set_shell_command_args_array directory_chmod_command_options_array \
                "directory_chmod_command_options" "$directory_chmod_command_options" || return $?

            tudo_log 3 "Setting '${directory_chmod_command_options_array[*]}' permissions to $directory_path_label directory at '$directory_path' directory"
            chmod "${directory_chmod_command_options_array[@]}" "$directory_path"
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "Failed to set permissions of $directory_path_label directory at '$directory_path'"
                return $return_value
            fi
        fi

        # Set subdirectories ownership
        if [[ "$sub_directories_chown_command_options" != "-" ]]; then
            local -a sub_directories_chown_command_options_array=()
            tudo_set_shell_command_args_array sub_directories_chown_command_options_array \
                "sub_directories_chown_command_options" "$sub_directories_chown_command_options" || return $?

            tudo_log 3 "Setting '${sub_directories_chown_command_options_array[*]}' ownership to $directory_path_label directory at '$directory_path' subdirectories"
            (tudo_trim_env_for_xargs && find "$directory_path" -type d -print0 | xargs -0 -r -- chown "${sub_directories_chown_command_options_array[@]}" --)
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "Failed to set ownership of subdirectories in $directory_path_label directory at '$directory_path'"
                return $return_value
            fi
        fi

        # Set subdirectories permissions
        if [[ "$sub_directories_chmod_command_options" != "-" ]]; then
            local -a sub_directories_chmod_command_options_array=()
            tudo_set_shell_command_args_array sub_directories_chmod_command_options_array \
                "sub_directories_chmod_command_options" "$sub_directories_chmod_command_options" || return $?

            tudo_log 3 "Setting '${sub_directories_chmod_command_options_array[*]}' permissions to $directory_path_label directory at '$directory_path' subdirectories"
            (tudo_trim_env_for_xargs && find "$directory_path" -type d -print0 | xargs -0 -r -- chmod "${sub_directories_chmod_command_options_array[@]}" --)
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "Failed to set permissions of subdirectories in $directory_path_label directory at '$directory_path'"
                return $return_value
            fi
        fi

        # Set subfiles ownership
        if [[ "$sub_files_chown_command_options" != "-" ]]; then
            local -a sub_files_chown_command_options_array=()
            tudo_set_shell_command_args_array sub_files_chown_command_options_array \
                "sub_files_chown_command_options" "$sub_files_chown_command_options" || return $?

            tudo_log 3 "Setting '${sub_files_chown_command_options_array[*]}' ownership to $directory_path_label directory at '$directory_path' subfiles"
            (tudo_trim_env_for_xargs && find "$directory_path" -type f -print0 | xargs -0 -r -- chown "${sub_files_chown_command_options_array[@]}" --)
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "Failed to set ownership of subfiles in $directory_path_label directory at '$directory_path'"
                return $return_value
            fi
        fi

        # Set subfiles permissions
        if [[ "$sub_files_chmod_command_options" != "-" ]]; then
            local -a sub_files_chmod_command_options_array=()
            tudo_set_shell_command_args_array sub_files_chmod_command_options_array \
                "sub_files_chmod_command_options" "$sub_files_chmod_command_options" || return $?

            tudo_log 3 "Setting '${sub_files_chmod_command_options_array[*]}' permissions to $directory_path_label directory at '$directory_path' subfiles"
            (tudo_trim_env_for_xargs && find "$directory_path" -type f -print0 | xargs -0 -r -- chmod "${sub_files_chmod_command_options_array[@]}" --)
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "Failed to set permissions of subfiles in $directory_path_label directory at '$directory_path'"
                return $return_value
            fi
        fi
    fi


    # Run file type tests with test command
    if [[ "$file_type_tests" != "-" ]]; then
        # tudo_run_file_type_tests_on_path label path log_file_tests_failure_errors show_stat_output_on_file_tests_failure check_if_absolute_path file_type_tests
        tudo_run_file_type_tests_on_path "$directory_path_label" "$directory_path" 1 1 0 "$file_type_tests" || return $?
    fi


    return 0

}

##
# `tudo_create_modify_validate_file` `<file_path_label>` `<file_path>` `<check_if_absolute_path>` `<create_file_if_it_does_not_exist>` `<file_creation_command_options>` `<file_content>` `<only_set_perms_and_ownership_on_creation>` `<file_chown_command_options>` `<file_chmod_command_options>` `<file_type_tests>`
##
tudo_create_modify_validate_file() {

    local return_value

    # If argument count is not 10
    if [ $# -ne 10 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_create_modify_validate_file'"
        return 1
    fi

    #tudo_log_literal 3 "\nRunning tudo_create_modify_validate_file"

    local file_path_label="$1"
    local file_path="$2"
    local check_if_absolute_path="$3"
    local create_file_if_it_does_not_exist="$4"
    local file_creation_command_options="$5"
    local file_content="$6"
    local only_set_perms_and_ownership_on_creation="$7"
    local file_chown_command_options="$8"
    local file_chmod_command_options="$9"
    local file_type_tests="${10}"

    local file_created=0

    # If create_file_if_it_does_not_exist is not set to 0 or 1
    if [[ "$create_file_if_it_does_not_exist" != "0" ]] && [[ "$create_file_if_it_does_not_exist" != "1" ]]; then
        tudo_log_errors "create_file_if_it_does_not_exist '$create_file_if_it_does_not_exist' passed to 'tudo_create_modify_validate_file' is not equal to '0' or '1'"
        return 1
    fi

    # If only_set_perms_and_ownership_on_creation is not set to 0 or 1
    if [[ "$only_set_perms_and_ownership_on_creation" != "0" ]] && [[ "$only_set_perms_and_ownership_on_creation" != "1" ]]; then
        tudo_log_errors "only_set_perms_and_ownership_on_creation '$only_set_perms_and_ownership_on_creation' passed to 'tudo_create_modify_validate_file' is not equal to '0' or '1'"
        return 1
    fi

    # If check_if_absolute_path is enabled and file_path is not a valid absolute path
    local valid_absolute_path_regex='^(/[^/]+)+$'
    if [[ "$check_if_absolute_path" == "1" ]] && [[ ! "$file_path" =~ $valid_absolute_path_regex ]]; then
        tudo_log_errors "The '$file_path_label' file '$file_path' is not an absolute path"
        return 2
    fi

    # Check if a non-file file exists at file path
    if [ -e "$file_path" ] && [ ! -f "$file_path" ]; then
        tudo_log_errors "A non-regular file exists at $file_path_label '$file_path'"
        return 1
    fi

    # If file does not exist
    if [ ! -f "$file_path" ]; then
        # If create_file_if_it_does_not_exist is enabled, then create file
        if [[ "$create_file_if_it_does_not_exist" == "1" ]]; then
            tudo_log 3 "Creating $file_path_label '$file_path' file"

            local -a file_creation_command_options_array
            if [[ "$file_creation_command_options" != "-" ]]; then
                local -a file_creation_command_options_array=()
                tudo_set_shell_command_args_array file_creation_command_options_array \
                    "file_creation_command_options" "$file_creation_command_options" || return $?
            fi

            # If file_creation_options is set, then pass it to printf
            if [ ${#file_creation_command_options_array[@]} -ne 0 ]; then
                printf "${file_creation_command_options_array[@]}" "$file_content" > "$file_path"
            else
                printf "$file_content" > "$file_path"
            fi
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "Failed to create $file_path_label file at '$file_path'"
                return $return_value
            fi

            if [ ! -f "$file_path" ]; then
                tudo_log_errors "Failed to find $file_path_label file at '$file_path' after creation"
                return 1
            fi

            file_created=1
        else
            tudo_log_errors "Failed to find $file_path_label file at '$file_path'"
            return 1
        fi
    else
        if [[ "$create_file_if_it_does_not_exist" == "1" ]]; then
            tudo_log 3 "The $file_path_label file already exists at '$file_path'"
        else
            tudo_log 3 "The $file_path_label file exists at '$file_path'"
        fi
    fi

    # Check if file did not already exist or was not created successfully
    if [ ! -f "$file_path" ]; then
        tudo_log_errors "Failed to find $file_path_label file at '$file_path'"
        return 1
    fi

    # If only_set_perms_and_ownership_on_creation is enabled and file was not created
    if  [[ "$only_set_perms_and_ownership_on_creation" == "1" ]] && [[ "$file_created" == "0" ]]; then
        tudo_log 3 "Skipping setting ownership and permission for $file_path_label file since it was not created"
    else
        # Set file ownership
        if [[ "$file_chown_command_options" != "-" ]]; then
            local -a file_chown_command_options_array=()
            tudo_set_shell_command_args_array file_chown_command_options_array \
                "file_chown_command_options" "$file_chown_command_options" || return $?

            tudo_log 3 "Setting '${file_chown_command_options_array[*]}' ownership to $file_path_label '$file_path' file"
            chown "${file_chown_command_options_array[@]}" "$file_path"
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "Failed to set ownership of $file_path_label file at '$file_path'"
                return $return_value
            fi
        fi

        # Set file permissions
        if [[ "$file_chmod_command_options" != "-" ]]; then
            local -a file_chown_command_options_array=()
            tudo_set_shell_command_args_array file_chmod_command_options_array \
                "file_chmod_command_options" "$file_chmod_command_options" || return $?

            tudo_log 3 "Setting '${file_chmod_command_options_array[*]}' permissions to $file_path_label '$file_path' file"
            chmod "${file_chmod_command_options_array[@]}" "$file_path"
            return_value=$?
            if [ $return_value -ne 0 ]; then
                tudo_log_errors "Failed to set permissions of $file_path_label file at '$file_path'"
                return $return_value
            fi
        fi
    fi


    # Run file type tests with test command
    if [[ "$file_type_tests" != "-" ]]; then
        # tudo_run_file_type_tests_on_path label path log_file_tests_failure_errors show_stat_output_on_file_tests_failure check_if_absolute_path file_type_tests
        tudo_run_file_type_tests_on_path "$file_path_label" "$file_path" 1 1 0 "$file_type_tests" || return $?
    fi


    return 0

}

##
# `tudo_expand_termux_path` `<variable_name>` `<label>` `<path>` `<termux_prefix>` `<termux_home>` `<canonicalize_path>`
##
tudo_expand_termux_path() {

    local return_value

    # If argument count is not 6
    if [ $# -ne 6 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_expand_termux_path'"
        return 1
    fi

    local variable_name="$1"
    local label="$2"
    local path_to_expand="$3"
    local termux_prefix="$4"
    local termux_home="$5"
    local canonicalize_path="$6"

    local absolute_path_to_expand
    local valid_absolute_path_regex='^(/[^/]+)+$'

    [[ "$path_to_expand" == "\$PREFIX/" ]] && path_to_expand="$termux_prefix" # Replace '$PREFIX/' with "$termux_prefix"
    [[ "$path_to_expand" == "~/" ]] && path_to_expand="$termux_home" # Replace '~/' with "$termux_home"

    path_to_expand="${path_to_expand/#\$PREFIX\//$termux_prefix\/}" # Replace '$PREFIX/*' with "$termux_prefix/*"
    path_to_expand="${path_to_expand/#~\//$termux_home\/}" # Replace '~/*' with "$termux_home/*"

    # If canonicalize_path equals "1" or (canonicalize_path equals "2" and path_to_expand is not a symlink
    if [[ "$canonicalize_path" == "1" ]] || { [[ "$canonicalize_path" == "2" ]] && [ ! -L "$path_to_expand" ]; }; then
        absolute_path_to_expand="$path_to_expand"
        path_to_expand="$(readlink -m -- "$path_to_expand")"
        return_value=$?
        if [ $return_value -ne 0 ] || [[ ! "$path_to_expand" =~ $valid_absolute_path_regex ]]; then
            tudo_log_errors "Failure while finding canonical path for path_to_expand '$absolute_path_to_expand'"
            tudo_log_errors "canonical_path_to_expand='$path_to_expand'"
            if [ $return_value -eq 0 ]; then
                return_value=1
            fi
            return $return_value
        fi
    elif [[ "$canonicalize_path" == "3" ]]; then
        # If path is relative to current working directory starting with `./` or `../`
        if [[ "${path_to_expand:0:2}" == "./" ]] || [[ "${path_to_expand:0:3}" == "../" ]]; then
            # Prepend current working directory
            if [[ "$CURRENT_WORKING_DIR" != "/" ]]; then
                path_to_expand="$CURRENT_WORKING_DIR/$path_to_expand"
            else
                path_to_expand="/$path_to_expand"
            fi
        fi

        # Replace duplicate path separators `//` with single `/`
        path_to_expand="${path_to_expand//\/\///}"
    fi

    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'

    # If variable_name does not equal "path_to_expand" and is valid bash variable_name
    if [[ "$variable_name" != "path_to_expand" ]] && [[ "$variable_name" =~ $valid_bash_variable_name_regex ]]; then
        # Set variable_name to path_to_expand
        printf -v "$variable_name" "%s" "$path_to_expand"
    else
        tudo_log_errors "variable_name '$1' passed to 'tudo_expand_termux_path' equals 'path_to_expand' or is not a valid bash variable name"
        return 1
    fi

}

##
# - The path will be first expanded by `tudo_expand_termux_path`. If the path is relative to current directory starting with `./` or `../`,
#   then it is prefixed with CURRENT_WORKING_DIR due to passing `canonicalize_path=3`.
# - If an absolute path is returned by `tudo_expand_termux_path`, then it checked to see if it is for an executable file,
#   otherwise executable is searched in all the paths in `paths_to_check_for_executable` list (ideally `$PATH` variable).
# - If an executable is found, then that is returned, otherwise function fails with 112.
#
# `tudo_find_absolute_path_for_executable_and_validate` `<variable_name>` `<label>` `<path>` `<paths_to_check_for_executable>` `<termux_prefix>` `<termux_home>`
##
tudo_find_absolute_path_for_executable_and_validate() {

    local return_value

    # If argument count is not 6
    if [ $# -ne 6 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_find_absolute_path_for_executable_and_validate'"
        return 1
    fi

    local variable_name="$1"
    local label="$2"
    local path="$3"
    local paths_to_check_for_executable="$4"
    local termux_prefix="$5"
    local termux_home="$6"

    local executable_found=0
    local absolute_path
    local expanded_path
    local valid_absolute_path_regex='^(/[^/]+)+$'

    # Replace "$PREFIX/" or "~/" prefix with termux absolute paths in path
    tudo_expand_termux_path "expanded_path" "${label}_PATH" "$path" "$termux_prefix" "$termux_home" 3
    return_value=$?
    if [ $return_value -ne 0 ]; then
        tudo_log_errors "Failed to expand ${label}_PATH '$path'"
        return $return_value
    fi

    tudo_log 3 "${label}_EXPANDED_PATH='$expanded_path'"

    if [[ "$expanded_path" =~ $valid_absolute_path_regex ]]; then
        absolute_path="$expanded_path"
        test -f "$absolute_path" && test -r "$absolute_path" && test -x "$absolute_path"
        return_value=$?
        if [ $return_value -ne 0 ] && [ $return_value -ne 1 ]; then
            tudo_log_errors "Failed to run the following test types on the file '${label}_PATH' at path '$absolute_path': [regular file], [readable], [executable]"
            return $return_value
        elif [ $return_value -eq 0 ]; then
            tudo_log 3 "Executable found at '$absolute_path'"
            executable_found=1
        fi
    fi

    # If executable still not found and original path was just a basename, then check if path exists in PATH_TO_EXPORT
    if [[ "$executable_found" == "0" ]] && [[ "$path" != *'/'* ]]; then
        # Check if paths_to_check_for_executable is valid
        local invalid_value_for_path_variable_regex='^:|:$|.*::.*|.*'$'\n''.*'
        if [[ "$paths_to_check_for_executable" =~ $invalid_value_for_path_variable_regex ]]; then
            tudo_log_errors "PATHS_TO_CHECK_FOR_EXECUTABLE '$paths_to_check_for_executable' is invalid, it cannot start or end with a colon, contain two consecutive colons ':' or contain newline characters"
            return 1
        fi

        tudo_log 3 "Checking for '$path' executable at following paths: '$paths_to_check_for_executable'"

        # Check if path is a binary or any executable in paths_to_check_for_executable
        for path_to_check_for_executable in ${paths_to_check_for_executable//:/ }; do
            absolute_path="$path_to_check_for_executable/$path"
            tudo_log 3 "'$absolute_path'"

            test -f "$absolute_path" && test -r "$absolute_path" && test -x "$absolute_path"
            return_value=$?
            if [ $return_value -ne 0 ] && [ $return_value -ne 1 ]; then
                tudo_log_errors "Failed to run the following test types on the file '${label}_PATH' at path '$absolute_path': [regular file], [readable], [executable]"
                return $return_value
            elif [ $return_value -eq 0 ]; then
                tudo_log 3 "Executable found at '$absolute_path'"
                executable_found=1
                break
            fi
        done
    fi

    # If executable is not found, then exit with error
    # since this is the final path
    if [[ "$executable_found" != "1" ]]; then
        return 112
    fi

    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'

    # If variable_name does not equal "absolute_path" and is valid bash variable_name
    if [[ "$variable_name" != "absolute_path" ]] && [[ "$variable_name" =~ $valid_bash_variable_name_regex ]]; then
        # Set variable_name to absolute_path
        printf -v "$variable_name" "%s" "$absolute_path"
    else
        tudo_log_errors "variable_name '$1' passed to 'tudo_find_absolute_path_for_executable_and_validate' equals 'absolute_path' or is not a valid bash variable name"
        return 1
    fi

}

##
# Validate if path is under TERMUX_ROOTFS and is not backlisted
#
# `tudo_validate_path_is_a_whitelisted_path_under_termux_rootfs` `<label>` `<path>`
##
tudo_validate_path_is_a_whitelisted_path_under_termux_rootfs() {

    local return_value

    # If argument count is not 2
    if [ $# -ne 2 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_validate_path_is_a_whitelisted_path_under_termux_rootfs'"
        return 1
    fi

    local label="$1"
    local path="$2"

    local termux_rootfs_escaped
    local termux_home_escaped
    local termux_prefix_escaped

    # Android app package names can only contain `[a-zA-Z0-9_]` characters
    # with a dot `.` between segments and each segment must start with
    # an alphabet. (`^[a-zA-Z][a-zA-Z0-9_]*(\.[a-zA-Z][a-zA-Z0-9_]*)+$`).
    # So only a dot `.` character in termux paths would need to be escaped in a regex.
    # - https://developer.android.com/build/configure-app-module#set-application-id
    # - https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:frameworks/base/core/java/android/content/pm/parsing/ApkLiteParseUtils.java;l=671-676
    # - https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:frameworks/base/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java;l=63

    termux_rootfs_escaped="${TERMUX_ROOTFS//./\\.}" # Replace `.` with `\.`
    termux_rootfs_escaped="${termux_rootfs_escaped////[\\\/]+}" # Replace `/` with `[\/]+`

    termux_home_escaped="${TERMUX_HOME//./\\.}" # Replace `.` with `\.`
    termux_home_escaped="${termux_home_escaped////[\\\/]+}" # Replace `/` with `[\/]+`

    termux_prefix_escaped="${TERMUX_PREFIX//./\\.}" # Replace `.` with `\.`
    termux_prefix_escaped="${termux_prefix_escaped////[\\\/]+}" # Replace `/` with `[\/]+`

    local valid_path_under_termux_rootfs_regex='^'"$termux_rootfs_escaped"'[\/]+.+'
    local blacklisted_path_in_termux_rootfs_regex='^(('"$termux_home_escaped"'[\/]+\.(cache|config|local|termux))|('"$termux_prefix_escaped"')|('"$termux_prefix_escaped"'[\/]+.*))([\/]+)?$'

    # If path same as TERMUX_ROOTFS
    if [[ "$path" == "$TERMUX_ROOTFS" ]]; then
        tudo_log 3 "$label '$path' is the same as TERMUX_ROOTFS"
        return 2
    # If path is set to an absolute path under TERMUX_ROOTFS
    elif [[ "$path" =~ $valid_path_under_termux_rootfs_regex ]]; then
        # If path is set to a blacklist path under TERMUX_ROOTFS
        if [[ "$path" =~ $blacklisted_path_in_termux_rootfs_regex ]]; then
            tudo_log 3 "$label '$path' matches one of following blacklisted paths:"
            tudo_log 3 "'$TERMUX_HOME/.{cache,config,local,termux}', '$TERMUX_PREFIX/*'"
            return 2
        else
            return 0
        fi
    else
        return 3
    fi

}

##
# `tudo_parse_and_validate_path_variable` `<variable_name>` `<label>` `<path>` `<remove_duplicates>`
##
tudo_parse_and_validate_path_variable() {

    local return_value

    # If argument count is not 4
    if [ $# -ne 4 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_parse_and_validate_path_variable'"
        return 1
    fi

    local variable_name="$1"
    local label="$2"
    local path_to_parse="$3"
    local remove_duplicates="$4"

    # If remove_duplicates is enabled
    if [[ "$remove_duplicates" == "1" ]]; then
        # Remove duplicates from path_to_parse
        path_to_parse="$(printf "%s" "$path_to_parse" | awk -v RS=: -v ORS= '!a[$0]++ {if (NR>1) printf(":"); printf("%s", $0) }' )"
        return_value=$?
        if [ $return_value -ne 0 ]; then
            tudo_log_errors "Failed to remove duplicates from $label '$path_to_parse'"
            return $return_value
        fi
    fi

    # Check if path_to_parse is valid
    local invalid_value_for_path_variable_regex='^:|:$|.*::.*|.*'$'\n''.*'
    if [[ "$path_to_parse" =~ $invalid_value_for_path_variable_regex ]]; then
        tudo_log_errors "$label '$path_to_parse' is invalid, it cannot start or end with a colon, contain two consecutive colons ':' or contain newline characters"
        return 1
    fi

    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'

    # If variable_name does not equal "path_to_parse" and is valid bash variable_name
    if [[ "$variable_name" != "path_to_parse" ]] && [[ "$variable_name" =~ $valid_bash_variable_name_regex ]]; then
        # Set variable_name to path
        printf -v "$variable_name" "%s" "$path_to_parse"
    else
        tudo_log_errors "variable_name '$1' passed to 'tudo_parse_and_validate_path_variable' equals 'path_to_parse' or is not a valid bash variable name"
        return 1
    fi

}



##
# Get/Set/Unset variable names and values for `TERMUX*__` and other
# scoped environment variables exported by different Termux runtime
# components, with support for fallback values and validation of
# values.
#
# The `extended_validator` logic is based on `libalteran-sh`
# `bash___shell__validate_variable_with_extended_validator()` function.
#
# **See Also:**
# - https://github.com/termux/termux-core-package/blob/master/site/pages/en/projects/docs/usage/utils/termux-scoped-env-variable.md
# - https://github.com/termux/termux-core-package/blob/master/src/scripts/termux-scoped-env-variable.bash.in
# - https://github.com/termux/termux-packages/blob/master/packages/termux-core/src/scripts/termux_core__bash__termux_scoped_env_variable
#
#
# `termux_core__bash__termux_scoped_env_variable` `get-name` \
#     `<output_mode>` \
#     `<scoped_var_scope_mode>` `<scoped_var_sub_name>`
# `termux_core__bash__termux_scoped_env_variable` `get-value` \
#     `<output_mode>` \
#     `<scoped_var_scope_mode>` `<scoped_var_sub_name>` \
#     `<extended_validator>` [`<default_values...>`]
##
termux_core__bash__termux_scoped_env_variable() {

    local return_value

    local command_type="${1:-}"
    local command_action="${command_type%%-*}"
    [ $# -gt 0 ] && shift 1

    if [ "$command_type" = "get-name" ]; then
        local output_mode="${1:-}"
        local scoped_var_scope_mode="${2:-}"
        local scoped_var_sub_name="${3:-}"

        if [ $# -ne 3 ]; then
            echo "Invalid argument count $# for the 'get-name' command. \
The 'termux_core__bash__termux_scoped_env_variable' function expects 3 arguments." 1>&2
            printf 'Arguments: %s\n' "$*" 1>&2
            return 64 # EX__USAGE
        fi
    elif [ "$command_type" = "get-value" ]; then
        local output_mode="${1:-}"
        local scoped_var_scope_mode="${2:-}"
        local scoped_var_sub_name="${3:-}"
        local extended_validator="${4:-}"

        local validator_arg
        local validator_mode

        if [ $# -lt 4 ]; then
            echo "Invalid argument count $# for the 'get-value' command. \
The 'termux_core__bash__termux_scoped_env_variable' function expects minimum 4 arguments." 1>&2
            printf 'Arguments: %s\n' "$*" 1>&2
            return 64 # EX__USAGE
        fi

        # Remove args before `default_values` to be used in `var_value_cur` for loop below.
        shift 4

        case "$extended_validator" in
            '?'|'*')
                validator_arg=""
                validator_mode="$extended_validator"
                ;;
            'r+='?*|'r-='?*)
                validator_arg="${extended_validator:3}" # 3:end
                validator_mode="${extended_validator:0:3}" # 0:3
                ;;
            *)
                echo "The extended_validator '$extended_validator' \
argument passed to 'termux_core__bash__termux_scoped_env_variable' is not valid. \
It must either be equal to \`?\` or \`*\`, or a regex that starts with \`r+=\` or \`r-=\`." 1>&2
                return 64 # EX__USAGE
                ;;
        esac
    else
        echo "The command '$command_type' passed to 'termux_core__bash__termux_scoped_env_variable' is not valid." 1>&2
        return 64 # EX__USAGE
    fi

    local i
    local is_value_valid
    local scoped_var_root_scope_name=""
    local scoped_var_scope_name=""
    local scoped_var_sub_scope_name=""
    local scoped_var_name=""
    local scoped_var_set=""
    local scoped_var_value_invalid_error_suffix=""
    local var_value_cur

    # A valid environment variable name (like `TERMUX__VAR`) or a bash array variable (like `TERMUX__ARRAY[0]`).
    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'


    if [ "$command_action" = "get" ]; then
        if [ "$output_mode" != ">" ] && [ "$output_mode" != "-" ]; then
            # If `output_mode` is not a valid environment variable name.
            if [[ ! "$output_mode" =~ $valid_bash_variable_name_regex ]]; then
                echo "The output_mode '$output_mode' argument passed to \
'termux_core__bash__termux_scoped_env_variable' is not a valid environment variable name, or equal to \`>\` or \`-\`." 1>&2
                return 64 # EX__USAGE
            fi
        fi
    fi


    case "$scoped_var_scope_mode" in
        s=?*) scoped_var_scope_name="${scoped_var_scope_mode:2}";; # 2:end
        ss=?*) scoped_var_sub_scope_name="${scoped_var_scope_mode:3}";; # 3:end
        '') ;;
        *)
            echo "The scoped_var_scope_mode '$scoped_var_scope_mode' \
argument for the variable to $command_action passed to \
'termux_core__bash__termux_scoped_env_variable' is not valid. \
It must either be a supported component name starting with \`cn=\`, \
or an environment variable scope starting with \`s=\` or \`ss=\`." 1>&2
            return 64 # EX__USAGE
            ;;
    esac


    if [ -n "$scoped_var_scope_mode" ]; then
        if [ -n "$scoped_var_scope_name" ]; then
            # Generate the full name for the variable under the provided root and sub scope.
            scoped_var_name="${scoped_var_scope_name}${scoped_var_sub_name}"
        else
            # Generate the full name for the variable under the Termux root scope and provided sub scope.
            # If `TERMUX_ENV__S_ROOT` environment variable set.
            # shellcheck disable=SC2050
            if [ -n "${TERMUX_ENV__S_ROOT:-}" ]; then
                scoped_var_root_scope_name="$TERMUX_ENV__S_ROOT"
                if [[ ! "$scoped_var_root_scope_name" =~ $valid_bash_variable_name_regex ]]; then
                    echo "The TERMUX_ENV__S_ROOT environment variable value '$scoped_var_root_scope_name' \
while running 'termux_core__sh__termux_scoped_env_variable' is not a valid environment variable name." 1>&2
                    return 1
                fi
            # If `TERMUX_ENV__S_ROOT` placeholder got replaced during build time.
            elif [ "TERMUX_" != @"TERMUX_ENV__S_ROOT"@ ]; then
                scoped_var_root_scope_name="TERMUX_"
                if [[ ! "$scoped_var_root_scope_name" =~ $valid_bash_variable_name_regex ]]; then
                    echo "The TERMUX_ENV__S_ROOT build value '$scoped_var_root_scope_name' \
while running 'termux_core__sh__termux_scoped_env_variable' is not a valid environment variable name." 1>&2
                    return 1
                fi
            else
                scoped_var_root_scope_name="TERMUX_"
            fi

            scoped_var_name="${scoped_var_root_scope_name}${scoped_var_sub_scope_name}${scoped_var_sub_name}"
        fi

        if [[ ! "$scoped_var_name" =~ $valid_bash_variable_name_regex ]]; then
            echo "The name of the variable to $command_action '$scoped_var_name' generated in \
'termux_core__bash__termux_scoped_env_variable' is not a valid environment variable name." 1>&2
            return 64 # EX__USAGE
        fi


        # If command type equals `get-name`, then return the variable name and exit.
        if [ "$command_type" = "get-name" ]; then
            #echo "scoped_var_name=$scoped_var_name"
            if [ "$output_mode" = ">" ]; then
                printf "%s" "$scoped_var_name"
                return $?
            elif [ "$output_mode" != "-" ]; then
                printf -v "$output_mode" "%s" "$scoped_var_name"
                #eval "echo $output_mode=\"\${${output_mode}}\"" # Surround `${output_mode}` with `${}` in case its a base array variable name
                return $?
            else
                return 0
            fi
        fi
    else
        if [ "$command_type" = "get-name" ]; then
            echo "The scoped_var_scope_mode argument for the variable \
to $command_action passed for the '$command_type' command to \
'termux_core__bash__termux_scoped_env_variable' is not set." 1>&2
            return 64 # EX__USAGE
        fi
    fi


    # If command type equals `get-value`, then find the first valid in variable name/values passed.
    if [ "$command_type" = "get-value" ]; then
        # Loop on [`<expanded_scoped_var_name>` `<default_values>`] to
        # find the first valid value.
        i=0
        for var_value_cur in "$scoped_var_name" "$@"; do
            var_value_cur="${var_value_cur:-}"

            # If first loop, then expand the `scoped_var_name` to its value.
            if [ "$i" = 0 ] && [ -n "$scoped_var_name" ]; then
                # If mode is `*`, expand variable if it is set, or defined
                # but empty. Else if its not defined, then ignore it.
                if [ "$validator_mode" = "*" ]; then
                    eval '[ -n "${'"$scoped_var_name"'+x}" ] && scoped_var_set=1 || scoped_var_set=0'
                    if [ "$scoped_var_set" = "1" ]; then
                        var_value_cur="${!scoped_var_name:-}"
                    else
                        i=$((i + 1)); continue;
                    fi
                else
                    var_value_cur="${!scoped_var_name:-}"
                fi
            fi

            is_value_valid=0
            if [ "$validator_mode" = "r+=" ]; then
                if [[ "$var_value_cur" =~ $validator_arg ]]; then
                    is_value_valid=1
                fi
            elif [ "$validator_mode" = "r-=" ]; then
                if [[ ! "$var_value_cur" =~ $validator_arg ]]; then
                    is_value_valid=1
                fi
            else
                # If mode is `?` or `*`, and value is set,
                # or mode is `*` and value is not set.
                if [ -n "$var_value_cur" ] || [ "$validator_mode" = "*" ]; then
                    is_value_valid=1
                # Else if mode is `?`, and value is not set.
                else
                    is_value_valid=0
                fi
            fi

            if [ "$is_value_valid" = "1" ]; then
                #echo "var_value_cur=$var_value_cur"
                if [ "$output_mode" = ">" ]; then
                    printf "%s" "$var_value_cur"
                    return $?
                elif [ "$output_mode" != "-" ]; then
                    printf -v "$output_mode" "%s" "$var_value_cur"
                    #eval "echo $output_mode=\"\${${output_mode}}\"" # Surround `${output_mode}` with `${}` in case its a base array variable name
                    return $?
                else
                    return 0
                fi
            fi

            i=$((i + 1))
        done


        # If a valid value not found.

        if [ -n "$scoped_var_name" ]; then
            scoped_var_value_invalid_error_suffix=" that is read from the '\$$scoped_var_name' variable"
        fi
        if [ "$output_mode" != ">" ] && [ "$output_mode" != "-" ]; then
            # Set output variable in `output_mode` to an empty string
            # since it may already be set, as callers may try to use that
            # wrong value without checking the exit code.
            # We unset after reading the values, otherwise if
            # `scoped_var_name` is equal to output variable in
            # `output_mode`, then `scoped_var_name` would get unset before
            # its read.
            printf -v "$output_mode" "%s" "" || return $?

            echo "Failed to find a valid value to set to the '\$$output_mode' \
variable${scoped_var_value_invalid_error_suffix}." 1>&2
        else
            echo "Failed to find a valid value${scoped_var_value_invalid_error_suffix}." 1>&2
        fi
        return 81 # C_EX__NOT_FOUND
    fi

}

##
# Set a bash indexed array (`declared -a`) to shell command arguments
# defined as a string by splitting the string as normally done by the
# shell.
#
# This function is based on `libalteran-sh`
# `bash___shell__set_shell_command_args_array()`
# function, check it for more info and comments.
#
#
# `tudo_set_shell_command_args_array` \
#     `<command_args_array_variable_name>` \
#     `<command_args_label>` `<command_args_string>`
##
tudo_set_shell_command_args_array() {

    local return_value

    if [ $# -ne 3 ]; then
        tudo_log_errors "Invalid argument count to 'tudo_set_shell_command_args_array'"
        return 1
    fi

    local command_args_array_variable_name="$1"
    local command_args_label="$2"
    local command_args_string="$3"

    local command_arg
    local command_args_string_contains_shell_special_chars="false"
    local command_args_string_contains_space="false"
    local newline=$'\n'
    local space_containing_string_regex='[[:space:]]+'
    local shell_special_chars_containing_string_regex='[]["'\''*?!\]+'
    local xargs_command_output

    local -n  command_args_array="$command_args_array_variable_name" || return $?
    command_args_array=()


    if [[ -z "$command_args_string" ]]; then
        # Unset `nameref` to `command_args_array_variable_name`.
        unset -n  command_args_array || return $?
        return 0
    fi

    if [[ "$command_args_string" == *$'\n'* ]]; then
        tudo_log_errors "The $command_args_label value to be \
converted to a command array cannot contain a newline '\n' character:"
        tudo_log_errors "\`\`\`"
        tudo_log_errors "$command_args_string"
        tudo_log_errors "\`\`\`"
        return 64 # EX__USAGE
    fi


    if [[ "$command_args_string" =~ $shell_special_chars_containing_string_regex ]]; then
        command_args_string_contains_shell_special_chars="true"
    fi
    if [[ "$command_args_string" =~ $space_containing_string_regex ]]; then
        command_args_string_contains_space="true"
    fi

    if [[ "$command_args_string_contains_shell_special_chars" == "true" ]] || \
            [[ "$command_args_string_contains_space" == "true" ]]; then

        # Use `xargs` if command args string contains whitespaces or
        # shell special characters.
        if [[ "$command_args_string_contains_shell_special_chars" == "true" ]]; then
            if [[ -z "$TUDO_XARGS_PATH" ]]; then
                return_value=0
                TUDO_XARGS_PATH="$(command -v "xargs")" || return_value=$?
                if [ $return_value -ne 0 ]; then
                    tudo_log_errors "Failed to find 'xargs' for converting $command_args_label value to a command array."
                    return $return_value
                fi
            fi

            # Android `toybox` provided `xargs` does not parse arguments
            # properly and single and double quotes around arguments
            # remain, nor do backslash escapes work.
            # Termux `findutils` package supplied `xargs` does not
            # have such issues, so we ignore the check for it.
            # `/system/bin/xargs` may get called if current shell has
            # `/system/bin` in `$PATH` instead of or before Termux bin path.
            if [[ "$TUDO_XARGS_PATH" != "$TERMUX_BIN/xargs" ]]; then
                # The logic to check if `xargs` parsing is valid is based
                # on `libalteran-sh` `bash___shell__set_is_xargs_command_args_parsing_valid()`
                # function, check it for more info and comments.
                return_value=0
                xargs_command_output="$(tudo_trim_env_for_xargs && \
                    printf "%s" "'' 'arg' '' 'arg with space' 'arg surround by single quote' \"arg surround by double quote\" 'arg with '\'' single quote' 'arg with \" double quote' 'arg with \" double quote surround by single quote' \"arg with ' single quote surround by double quote\" arg\ with\ escaped\ space 'arg with backslash \\ and forward slash / surround by single quote' \"arg with backslash \\ and forward slash / surround by double quote\" \\/ \\\\ ''" | \
                    xargs -r -n1 -- printf "%s\n" && echo -n x)" || return_value=$?
                if [ $return_value -ne 0 ]; then
                    tudo_log_errors "Failed to check if xargs command args parsing is valid."
                    tudo_log_errors "xargs_command_output=\`$xargs_command_output\`"
                    return $return_value
                fi

                if [[ "${xargs_command_output%x}" != "${newline}arg${newline}${newline}arg with space${newline}arg surround by single quote${newline}arg surround by double quote${newline}arg with ' single quote${newline}arg with \" double quote${newline}arg with \" double quote surround by single quote${newline}arg with ' single quote surround by double quote${newline}arg with escaped space${newline}arg with backslash \ and forward slash / surround by single quote${newline}arg with backslash \\ and forward slash / surround by double quote${newline}/${newline}\\${newline}" ]]; then
                    tudo_log_errors "The $command_args_label value cannot be \
converted to a command array in current execution environment as it contains \
shell special characters and 'xargs' command args parsing is not valid:"
                    tudo_log_errors "\`\`\`"
                    tudo_log_errors "$command_args_string"
                    tudo_log_errors "\`\`\`"
                    tudo_log_errors "xargs path: \`$(command -v "xargs" || true)\`"
                    tudo_log_errors "xargs version: \`$({ xargs --version 2>/dev/null || true; } | head -n 1)\`"
                    return 1
                fi
            fi

            command_arg="READ_ERROR"
            return_value=0
            while IFS= read -r command_arg; return_value=$?; [[ $return_value -eq 0 ]]; do
                command_args_array+=("$command_arg")
            done < <({ tudo_trim_env_for_xargs && \
                printf "%s\n" "$command_args_string" | \
                xargs -r -n1 -- printf "%s\n"; } || echo -n "CMD_ERROR")
            if [[ -n "${command_arg:-}" ]] || [ $return_value -ne 1 ]; then
                tudo_log_errors "Failed to create command array for \
command arguments string \`$command_args_string\`."
                [[ -n "${command_arg:-}" ]] && tudo_log_errors "Error type: '$command_arg'"
                if [[ -n ${!:-} ]]; then
                    wait "$!" || true
                fi
                return 1
            fi
        else
            # Avoid creating subshell and external call to xargs if
            # command args string contains whitespaces but does not
            # contain shell special characters and rely on whitespace
            # splitting of arguments.
            local old_ifs="$IFS"
            IFS=$' \t\n'
            # shellcheck disable=SC2206
            command_args_array=( $command_args_string )
            IFS="$old_ifs"
        fi
    else
        # Avoid creating subshell and external call to xargs if
        # command args string does not contain whitespaces or shell
        # special characters.
        command_args_array=( "$command_args_string" )
    fi

    # Unset `nameref` to `command_args_array_variable_name`.
    unset -n  command_args_array || return $?

    return 0

}

##
# Trim exported environment variables before running `xargs` to
# prevent `environment is too large for exec` error on Android `< 6`.
#
# On Android `5`, `getconf ARG_MAX` equals `4096` and `xargs` always
# fails to run.
#
# Only `PATH`, `$LD_LIBRARY_PATH` and `$LD_PRELOAD` variables are kept,
# and all other variables are unset.
#
# - https://www.gnu.org/software/findutils/manual/html_node/find_html/Error-Messages-From-xargs.html
##
tudo_trim_env_for_xargs() {

    # If on Android `< 6`
    if [ "$ANDROID__BUILD_VERSION_SDK" -lt 23 ]; then
        local env_variables
        env_variables="$(compgen -e | grep -v -E "^PATH|LD_LIBRARY_PATH|LD_PRELOAD$")" || return $?
        if [ -n "$env_variables" ]; then
            # shellcheck disable=SC2086
            unset $env_variables
        fi
    fi

}



##
# `tudo_replace_comma_alternative_chars_with_commas_in_string` `<string>`
##
tudo_replace_comma_alternative_chars_with_commas_in_string() {

    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'

    # If $1 is valid bash variable_name
    if [[ "$1" =~ $valid_bash_variable_name_regex ]]; then
        # Set variable_name stored in $1 to variable_value in $2 after replacing all COMMA_ALTERNATIVE characters with a comma ',' in $2
        printf -v "$1" "%s" "${2//$COMMA_ALTERNATIVE/,}"
    else
        tudo_log_errors "variable_name '$1' passed to 'tudo_replace_comma_alternative_chars_with_commas_in_string' is not a valid bash variable name"
    fi

}

##
# `tudo_trim_trailing_newlines` `<variable_name>` `<variable_value>`
##
tudo_trim_trailing_newlines() {

    local extglob_was_unset=1
    shopt extglob >/dev/null && extglob_was_unset=0 # Check if 'extglob' is currently set
    (( extglob_was_unset )) && shopt -s extglob # Set 'extglob', if currently unset

    local valid_bash_variable_name_regex='^[a-zA-Z_][a-zA-Z0-9_]*(\[[0-9]+\])?$'

    # If $1 is valid bash variable_name
    if [[ "$1" =~ $valid_bash_variable_name_regex ]]; then
        # Set variable_name stored in $1 to variable_value in $2 without trailing newline and carriage return characters
        printf -v "$1" "%s" "${2%%*([$'\r\n'])}"
    else
        tudo_log_errors "variable_name '$1' passed to 'tudo_trim_trailing_newlines' is not a valid bash variable name"
    fi

    (( extglob_was_unset )) && shopt -u extglob # Unset 'extglob', if previously unset

}

##
# `tudo_process_script_arguments` [`<argument...>`]
##
tudo_process_script_arguments() {

    local opt; local opt_arg; local OPTARG=""; local OPTIND=1;

    # Parse options to main command
    while getopts ":hqvaAbBcdeEfFHilLnNoOpPrsStT-:" opt; do
        case "${opt}" in
            -)
                case "${OPTARG}" in *?=*) opt_arg="${OPTARG#*=}";; *) opt_arg="";; esac
                case "${OPTARG}" in
                    help-extra)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        tudo_show_help_extra || return $?
                        TUDO_NOOP_COMMAND=1; return 0
                        ;;
                    help-extra=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    help)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        tudo_show_help || return $?
                        TUDO_NOOP_COMMAND=1; return 0
                        ;;
                    help=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    quiet)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        TUDO_LOG_LEVEL=0
                        ;;
                    quiet=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    version)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        echo "tudo version=$TUDO__VERSION org=agnostic-apollo project=tudo"
                        TUDO_NOOP_COMMAND=1; return 0
                        ;;
                    version=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    comma-alternative=?*)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        COMMA_ALTERNATIVE="$opt_arg"
                        ;;
                    comma-alternative | comma-alternative=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    dry-run)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        TUDO_DRY_RUN=1
                        ;;
                    dry-run=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    export-paths=?*)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        tudo_trim_trailing_newlines "TUDO_ADDITIONAL_PATHS_TO_EXPORT" "$opt_arg"
                        ;;
                    export-paths | export-paths=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    export-ld-lib-paths=?*)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        tudo_trim_trailing_newlines "TUDO_ADDITIONAL_LD_LIBRARY_PATHS_TO_EXPORT" "$opt_arg"
                        ;;
                    export-ld-lib-paths | export-ld-lib-paths=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    hold)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        HOLD_STRING_AFTER_TUDO=""
                        HOLD_AFTER_TUDO=1
                        ;;
                    hold=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        tudo_trim_trailing_newlines "HOLD_STRING_AFTER_TUDO" "$val"
                        HOLD_AFTER_TUDO=1
                        ;;
                    hold=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    hold-if-fail)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        HOLD_ONLY_ON_FAILURE=1
                        ;;
                    hold-if-fail=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    list-interactive-shells)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        echo "$TUDO_SUPPORTED_INTERACTIVE_SHELLS"
                        TUDO_NOOP_COMMAND=1; return 0
                        ;;
                    list-interactive-shells=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    list-script-shells)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        echo "$TUDO_SUPPORTED_SCRIPT_SHELLS"
                        TUDO_NOOP_COMMAND=1; return 0
                        ;;
                    list-script-shells=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    no-create-hist)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        TUDO_SHELLS_AUTOMATICALLY_CREATE_HISTORY_FILES=0
                        ;;
                    no-create-hist=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    no-create-rc)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        TUDO_SHELLS_AUTOMATICALLY_CREATE_RC_FILES=0
                        ;;
                    no-create-rc=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    no-hist)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        TUDO_SHELLS_HISTORY_ENABLED=0
                        ;;
                    no-hist=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    no-log-args)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        DISABLE_ARGUMENTS_LOGGING=1
                        ;;
                    no-log-args=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    keep-temp)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        DO_NOT_DELETE_TUDO_TEMP_DIRECTORY_ON_EXIT=1
                        ;;
                    keep-temp=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    post-shell=?*)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        tudo_trim_trailing_newlines "TUDO_POST_SHELL" "$opt_arg"
                        ;;
                    post-shell | post-shell=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    post-shell-home=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        tudo_trim_trailing_newlines "TUDO_POST_SHELL_HOME" "$val"
                        CUSTOM_TUDO_POST_SHELL_HOME_SET=1
                        ;;
                    post-shell-home | post-shell-home=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    post-shell-options=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        tudo_set_shell_command_args_array TUDO_POST_SHELL_INTERACTIVE_ADDITIONAL_COMMAND_OPTIONS \
                            "'--post-shell-options' arg option" "$val" || return $?
                        ;;
                    post-shell-options | post-shell-options=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    post-shell-post-commands=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        ADDITIONAL_TUDO_POST_SHELL_POST_COMMANDS_TO_RUN="$val"
                        ;;
                    post-shell-post-commands | post-shell-post-commands=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    post-shell-pre-commands=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        ADDITIONAL_TUDO_POST_SHELL_PRE_COMMANDS_TO_RUN="$val"
                        ;;
                    post-shell-pre-commands | post-shell-pre-commands=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    post-shell-stdin-string=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        TUDO_POST_SHELL_STDIN_STRING="$val"
                        ;;
                    post-shell-stdin-string | post-shell-stdin-string=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    remove-prev-temp)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        REMOVE_PREVIOUS_TUDO_TEMP_FILES=1
                        ;;
                    remove-prev-temp=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    script-decode)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        FORCE_USE_TEMP_SCRIPT_FILE_FOR_CORE_SCRIPT=1
                        DECODE_CORE_SCRIPT_CONTENT=1
                        ;;
                    script-decode=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    script-name=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        tudo_trim_trailing_newlines "TUDO_CORE_SCRIPT_TEMP_FILENAME" "$val"
                        ;;
                    script-name | script-name=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    script-redirect=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        tudo_trim_trailing_newlines "TUDO_CORE_SCRIPT_REDIRECT_MODE" "$val"
                        ;;
                    script-redirect | script-redirect=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    shell=?*)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        tudo_trim_trailing_newlines "TUDO_SHELL" "$opt_arg"
                        ;;
                    shell | shell=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    shell-home=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        tudo_trim_trailing_newlines "TUDO_SHELL_HOME" "$val"
                        CUSTOM_TUDO_SHELL_HOME_SET=1
                        ;;
                    shell-home | shell-home=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    shell-options=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        tudo_set_shell_command_args_array TUDO_SHELL_ADDITIONAL_COMMAND_OPTIONS \
                            "'--shell-options' arg option" "$val" || return $?
                        ;;
                    shell-options | shell-options=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    shell-post-commands=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        ADDITIONAL_TUDO_SHELL_POST_COMMANDS_TO_RUN="$val"
                        ;;
                    shell-post-commands | shell-post-commands=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    shell-pre-commands=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        ADDITIONAL_TUDO_SHELL_PRE_COMMANDS_TO_RUN="$val"
                        ;;
                    shell-pre-commands | shell-pre-commands=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    shell-stdin-string=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        TUDO_SHELL_STDIN_STRING="$val"
                        ;;
                    shell-stdin-string | shell-stdin-string=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    sleep=?*)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        tudo_trim_trailing_newlines "SLEEP_TIME_AFTER_TUDO" "$opt_arg"
                        SLEEP_AFTER_TUDO=1
                        ;;
                    sleep | sleep=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    sleep-if-fail)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}'"
                        SLEEP_ONLY_ON_FAILURE=1
                        ;;
                    sleep-if-fail=*)
                        tudo_log_arg_errors "Arguments not allowed for flag option '--${OPTARG%=*}': \`--${OPTARG:-}\`."
                        tudo_exit_on_args_error || return $?
                        ;;
                    su-bin-path-add=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        if [[ "$val" == "0" ]]; then
                            TUDO_ADD_SU_BIN_PATH_TO_PATH_VARIABLE=0
                        else
                            TUDO_ADD_SU_BIN_PATH_TO_PATH_VARIABLE=1
                        fi
                        ;;
                    su-bin-path-add | su-bin-path-add=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    su-path=?*)
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        tudo_trim_trailing_newlines "TUDO_SU_PATH" "$opt_arg"
                        TUDO_ADD_SU_BIN_PATH_TO_PATH_VARIABLE=1
                        ;;
                    su-path | su-path=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    title=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        tudo_trim_trailing_newlines "TUDO_SHELL_TERMINAL_TITLE" "$val"
                        SET_TUDO_SHELL_TERMINAL_TITLE=1
                        ;;
                    title | title=)
                        TUDO_SHELL_TERMINAL_TITLE=""
                        SET_TUDO_SHELL_TERMINAL_TITLE=1
                        ;;
                    work-dir=?*)
                        val="$opt_arg"
                        tudo_log_args "Parsing option: '--${OPTARG%=*}', value: '${opt_arg}'"
                        # If PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES is enabled
                        if  [[ "$PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES" == "1" ]]; then
                            tudo_replace_comma_alternative_chars_with_commas_in_string "val" "$val"
                        fi
                        tudo_trim_trailing_newlines "TUDO_SHELL_WORKING_DIR" "$val"
                        ;;
                    work-dir | work-dir=)
                        tudo_log_arg_errors "No argument set for arg option '--${OPTARG%=*}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                    '')
                        tudo_log_args "Parsing option: '--'"
                        break # End of options `--`.
                        ;;
                    *)
                        tudo_log_arg_errors "Unknown option: '--${OPTARG:-}'."
                        tudo_exit_on_args_error || return $?
                        ;;
                esac
                ;;
            h)
                tudo_log_args "Parsing option: '-${opt}'"
                tudo_show_help || return $?
                TUDO_NOOP_COMMAND=1; return 0
                ;;
            q)
                tudo_log_args "Parsing option: '-${opt}'"
                TUDO_LOG_LEVEL=0
                ;;
            v)
                tudo_log_args "Parsing option: '-${opt}'"
                if [ "$TUDO_LOG_LEVEL" -lt "$TUDO_MAX_LOG_LEVEL" ]; then
                    TUDO_LOG_LEVEL=$((TUDO_LOG_LEVEL+1));
                else
                    tudo_log_arg_errors "Invalid option, max log level is $TUDO_MAX_LOG_LEVEL"
                    tudo_exit_on_args_error || return $?
                fi
                ;;
            a)
                tudo_log_args "Parsing option: '-${opt}'"
                A_FLAG_PASSED=1
                PATH_PRIORITY="android"
                ;;
            A)
                tudo_log_args "Parsing option: '-${opt}'"
                A_FLAG_PASSED=1
                PATH_PRIORITY="android"

                if [ "$SET_SECONDARY_PRIORITY_PATHS" == "1" ]; then
                    # If first '-A' option passed
                    SET_SECONDARY_PATHS=0
                else
                    # If '-AA' passed
                    SET_SECONDARY_PATHS=1
                fi
                SET_SECONDARY_PRIORITY_PATHS=0
                ;;
            b)
                tudo_log_args "Parsing option: '-${opt}'"
                GO_BACK_TO_LAST_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT=1
                ;;
            B)
                tudo_log_args "Parsing option: '-${opt}'"
                RUN_CORE_SCRIPT_IN_BACKGROUND=1
                ;;
            c)
                tudo_log_args "Parsing option: '-${opt}'"
                CLEAR_SHELL_AFTER_RUNNING_CORE_SCRIPT=1
                ;;
            d)
                tudo_log_args "Parsing option: '-${opt}'"
                DISABLE_STDIN_FOR_CORE_SCRIPT=1
                ;;
            e)
                tudo_log_args "Parsing option: '-${opt}'"
                EXIT_EARLY_IF_CORE_SCRIPT_FAILS=1
                ;;
            E)
                tudo_log_args "Parsing option: '-${opt}'"
                EXEC_TUDO_SHELL=1
                ;;
            f)
                tudo_log_args "Parsing option: '-${opt}'"
                FORCE_USE_TEMP_SCRIPT_FILE_FOR_CORE_SCRIPT=1
                ;;
            F)
                tudo_log_args "Parsing option: '-${opt}'"
                CORE_SCRIPT_IS_PATH_TO_SCRIPT_FILE=1
                ;;
            H)
                tudo_log_args "Parsing option: '-${opt}'"
                SAME_TUDO_POST_SHELL_HOME_AS_TUDO_SHELL_HOME=1
                ;;
            i)
                tudo_log_args "Parsing option: '-${opt}'"
                RUN_INTERACTIVE_POST_TUDO_SHELL_AFTER_RUNNING_CORE_SCRIPT=1
                ;;
            l)
                tudo_log_args "Parsing option: '-${opt}'"
                GO_TO_LAUNCHER_ACTIVITY_AFTER_RUNNING_CORE_SCRIPT=1
                ;;
            L)
                tudo_log_args "Parsing option: '-${opt}'"
                TUDO_EXPORT_ALL_EXISTING_PATHS_IN_LD_LIBRARY_PATH_VARIABLE=1
                ;;
            n)
                tudo_log_args "Parsing option: '-${opt}'"
                TUDO_CORE_SCRIPT_REDIRECT_MODE=3
                ;;
            N)
                tudo_log_args "Parsing option: '-${opt}'"
                TUDO_CORE_SCRIPT_REDIRECT_MODE=4
                ;;
            o)
                tudo_log_args "Parsing option: '-${opt}'"
                TUDO_CORE_SCRIPT_REDIRECT_MODE=0
                ;;
            O)
                tudo_log_args "Parsing option: '-${opt}'"
                TUDO_CORE_SCRIPT_REDIRECT_MODE=1
                ;;
            p)
                tudo_log_args "Parsing option: '-${opt}'"
                COMMAND_TYPE="path"
                COMMAND_TYPE_PATH_FORCED=1
                ;;
            P)
                tudo_log_args "Parsing option: '-${opt}'"
                TUDO_EXPORT_ALL_EXISTING_PATHS_IN_PATH_VARIABLE=1
                ;;
            r)
                tudo_log_args "Parsing option: '-${opt}'"
                PARSE_COMMANDS_AS_PER_RUN_COMMAND_INTENT_RULES=1
                ;;
            s)
                tudo_log_args "Parsing option: '-${opt}'"
                COMMAND_TYPE="script"
                ;;
            S)
                tudo_log_args "Parsing option: '-${opt}'"
                SAME_TUDO_POST_SHELL_AS_TUDO_SHELL=1
                ;;
            t)
                tudo_log_args "Parsing option: '-${opt}'"
                T_FLAG_PASSED=1
                PATH_PRIORITY="termux"
                ;;
            T)
                tudo_log_args "Parsing option: '-${opt}'"
                T_FLAG_PASSED=1
                PATH_PRIORITY="termux"

                if [ "$SET_SECONDARY_PRIORITY_PATHS" == "1" ]; then
                    # If first '-T' option passed
                    SET_SECONDARY_PATHS=0
                else
                    # If '-TT' passed
                    SET_SECONDARY_PATHS=1
                fi
                SET_SECONDARY_PRIORITY_PATHS=0
                ;;
            :)
                tudo_log_arg_errors "No argument passed for arg option '-$OPTARG'."
                tudo_exit_on_args_error || return $?
                ;;
            \?)
                tudo_log_arg_errors "Unknown option${OPTARG:+": '-${OPTARG:-}'"}."
                tudo_exit_on_args_error || return $?
                ;;
        esac
    done
    shift $((OPTIND - 1)) # Remove already processed arguments from arguments array

    # If arguments received
    if [ $# -ne 0 ]; then
        # If (COMMAND_TYPE_PATH_FORCED is not enabled and $1 equals "su" or "asu"
        if [[ "$COMMAND_TYPE_PATH_FORCED" != "1" ]] && { [[ "$1" == "su" ]] || [[ "$1" == "asu" ]]; }; then
            COMMAND_TYPE="$1"
            shift # Remove $1 from the arguments array

            # If more arguments are given
            if [ $# -ne 0 ]; then
                tudo_log_arg_errors "Unknown arguments to '$COMMAND_TYPE': '$*'"
                tudo_exit_on_args_error || return $?
            fi

            if [[ "$COMMAND_TYPE" == "su" ]] && [[ "$A_FLAG_PASSED" == "1" ]]; then
                tudo_log_arg_errors "Cannot pass '-a|-A' flags to 'su' command, use '-t|-T' flags instead"
                tudo_exit_on_args_error || return $?
            fi

            if [[ "$COMMAND_TYPE" == "asu" ]] && [[ "$T_FLAG_PASSED" == "1" ]]; then
                tudo_log_arg_errors "Cannot pass '-t|-T' flags to 'asu' command, use '-a|-A' flags instead"
                tudo_exit_on_args_error || return $?
            fi

        # If COMMAND_TYPE equals "path" or "script"
        elif [[ "$COMMAND_TYPE" == "path" ]] || [[ "$COMMAND_TYPE" == "script" ]]; then
            # Set rest of the arguments to the tudo script as TUDO_COMMAND
            TUDO_COMMAND=()
            local return_value
            local read_argument_from_fd
            local fd_number
            local i=1
            for arg in "$@"; do
                read_argument_from_fd=0

                # If process substitution was used to pass path to an fd file as argument that contains the actual argument value
                # and the fd is not of stdin, stdout or stderr
                if [[ "$arg" =~ ^/proc/self/fd/[0-9]+$ ]] && [[ ! "$arg" =~ ^/proc/self/fd/(0|1|2)$ ]]; then
                    fd_number="${arg##*/}"
                    #if fd is readable, then
                    if read -t 0 -u "$fd_number" 2>/dev/null; then
                        # Enable read_argument_from_fd
                        read_argument_from_fd=1

                        # If COMMAND_TYPE equals "script" and its the first argument
                        if [[ "$COMMAND_TYPE" == "script" ]] && [ $i -eq 1 ]; then
                            # Disable read_argument_from_fd since we are reading it here with cat
                            # fd can't be read again, seeking backwards is not possible
                            read_argument_from_fd=0

                            # Read core_script from fd in encoded form since it may contain non UTF-8 or binary data
                            encoded_arg="$(cat "$arg" | base64)"
                            return_value=$?
                            if [ $return_value -ne 0 ] && [ $return_value -ne 1 ]; then
                                tudo_log_arg_errors "Failure while encoding core_script received as argument"
                                return $return_value
                            fi

                            # Check if core_script contains non UTF-8 or binary data
                            # Decode data first before passing to grep
                            printf '%s' "$encoded_arg" | base64 -d | grep -axvq '.*'
                            return_value=$?
                            if [ $return_value -ne 0 ] && [ $return_value -ne 1 ]; then
                                tudo_log_arg_errors "Failure while checking if core_script contains non UTF-8 or binary data"
                                return $return_value
                            # If found
                            elif [ $return_value -eq 0 ]; then
                                # Enable use of temp script file for core_script and enable decoding
                                FORCE_USE_TEMP_SCRIPT_FILE_FOR_CORE_SCRIPT=1
                                DECODE_CORE_SCRIPT_CONTENT=1

                                # Set encoded data to arg
                                arg="$encoded_arg"
                            # If not found
                            else
                                # Set decoded data to arg
                                arg="$(printf '%s' "$encoded_arg" | base64 -d)"
                            fi
                        fi
                    fi
                fi

                # If read_argument_from_fd is enabled
                if [[ "$read_argument_from_fd" == "1" ]]; then
                    # Use the fd file content as argument value
                    TUDO_COMMAND+=( "$(<"$arg")" )
                else
                    # Directly use the argument value
                    TUDO_COMMAND+=("$arg")
                fi

                i=$((i + 1))
            done
            shift $# # Remove all remaining arguments from arguments array
        fi

    # Else show help
    else
        if [[ "$COMMAND_TYPE" == "script" ]]; then
            TUDO_COMMAND=()
        else
            tudo_show_help
            TUDO_NOOP_COMMAND=1; return 0
        fi
    fi

}

tudo_show_help() {

    cat <<'TUDO_HELP_EOF' | \
        sed \
            -e "s%[@]TERMUX__LNAME[@]%${TERMUX__LNAME}%g" \
            -e "s%[@]TERMUX_APP__NAME[@]%${TERMUX_APP__NAME}%g"
tudo stands for 'Termux app user do'.
It is a wrapper script to execute commands as the
'Termux app (u<userid>_a<appid>)' user in the
Termux app, like to drop to an interactive shell for any
of the supported shells, or to execute shell script files or their
text passed as an argument.


Usage:
  tudo [command_options] su
  tudo [command_options] asu
  tudo [command_options] [-p] <command> [command_args]
  tudo [command_options] -s <core_script> [core_script_args]


Available command_options:
  [ -h | --help ]    Display this help screen.
  [ --help-extra ]   Display more help about how tudo command works.
  [ -q | --quiet ]   Set log level to 'OFF'.
  [ -v | -vv ]       Set log level to 'DEBUG', 'VERBOSE'.
  [ --version ]      Display version.
  [ -a ]             Set priority to android paths for 'path' and
                     'script' command types. The '$PATH' variable will
                     contain all android bin paths followed all termux
                     bin paths. The '$LD_PRELOAD' variable will not be
                     set.
  [ -A ]             Set priority to android paths for 'asu', 'path'
                     and 'script' command types. The '$PATH' variable
                     will contain only '/system/bin' path. The
                     '$LD_PRELOAD' variable will not be set.
  [ -AA ]            Set priority to android paths for 'asu', 'path'
                     and 'script' command types. The '$PATH' variable
                     will contain all android bin paths. The
                     '$LD_PRELOAD' variable will not be set.
  [ -b ]             Go back to last activity after running core_script.
  [ -B ]             Run core_script in background.
  [ -c ]             Clear shell after running core_script.
  [ -d ]             Disable stdin for core_script.
  [ -e ]             Exit early if core_script fails.
  [ -E ]             Exec interactive shell or the path command.
  [ -f ]             Force use temp script file for core_script.
  [ -F ]             Consider core_script to be a path to script file
                     instead of script text.
  [ -H ]             Same tudo post shell home as tudo shell home.
  [ -i ]             Run interactive tudo post shell after running
                     core_script.
  [ -l ]             Go to launcher activtiy after running core_script.
  [ -L ]             Export all existing paths in '$LD_LIBRARY_PATH'
                     variable.
  [ -n ]             Redirect stderr to /dev/null for core_script.
  [ -N ]             Redirect stdout and stderr to /dev/null for
                     core_script.
  [ -o ]             Redirect stderr to stdout for core_script.
  [ -O ]             Redirect stdout to stderr for core_script.
  [ -p ]             Set 'path' as command type [default].
  [ -P ]             Export all existing paths in '$PATH' variable.
  [ -r ]             Parse commands as per RUN_COMMAND intent rules.
  [ -s ]             Set 'script' as command type.
  [ -S ]             Same tudo post shell as tudo shell.
  [ -t ]             Set priority to termux paths for 'path' and
                     'script' command types. The '$PATH' variable will
                     contain all termux bin paths followed all android
                     bin paths. The '$LD_PRELOAD' variable will
                     contain '$TERMUX__PREFIX/lib/libtermux-exec.so'.
  [ -T ]             Set priority to termux paths for 'su', 'path'
                     and 'script' command types. The '$PATH' variable
                     will contain only '$TERMUX__PREFIX/bin' path.
                     The '$LD_PRELOAD' variable will contain
                     '$TERMUX__PREFIX/lib/libtermux-exec.so'.
  [ -TT ]            Set priority to termux paths for 'su', 'path'
                     and 'script' command types. The '$PATH' variable
                     will contain all termux bin paths. The
                     '$LD_PRELOAD' variable will contain
                     '$TERMUX__PREFIX/lib/libtermux-exec.so'.
  [ --comma-alternative=<alternative> ]
                     Comma alternative character to be used for
                     the '-r' option instead of the default.
  [ --dry-run ]
                     Do not execute tudo commands.
  [ --export-paths=<paths> ]
                     Additional paths to export in '$PATH' variable,
                     separated with colons ':'.
  [ --export-ld-lib-paths=<paths> ]
                     Additional paths to export in '$LD_LIBRARY_PATH'
                     variable, separated with colons ':'.
  [ --hold[=<string>] ]
                     Hold tudo from exiting until string is entered,
                     defaults to any character if string is not passed.
  [ --hold-if-fail ]
                     If '--hold' option is passed, then only hold if
                     exit code of tudo does not equal '0'.
  [ --list-interactive-shells ]
                     Display list of supported interactive shells.
  [ --list-script-shells ]
                     Display list of supported script shells.
  [ --no-create-rc ]
                     Do not create rc files automatically.
  [ --no-create-hist ]
                     Do not create history files automatically.
  [ --no-hist ]
                     Do not save history for tudo shell and tudo post
                     shell.
  [ --no-log-args ]
                     Do not log arguments and core_script content
                     when log level is '>= DEBUG'.
  [ --keep-temp ]
                     Do not delete tudo temp directory on exit.
  [ --post-shell=<shell> ]
                     Name or absolute path for tudo post shell.
  [ --post-shell-home=<path> ]
                     Absolute path for tudo post shell home.
  [ --post-shell-options=<options> ]
                     Additional options to pass to tudo post shell.
  [ --post-shell-post-commands=<commands> ]
                     Bash commands to run after tudo post shell.
  [ --post-shell-pre-commands=<commands> ]
                     Bash commands to run before tudo post shell.
  [ --post-shell-stdin-string=<string> ]
                     String to pass as stdin to tudo post shell.
  [ --remove-prev-temp ]
                     Remove temp files and directories created on
                     previous runs of tudo command.
  [ --script-decode ]
                     Consider the core_script as base64
                     encoded that should be decoded before execution.
  [ --script-name=<name> ]
                     Filename to use for the core_script temp file
                     created in '.tudo.temp.XXXXXX' directory instead
                     of 'tudo_script__core_script'.
  [ --script-redirect=<mode/string> ]
                     Core_script redirect mode for stdout and stderr.
  [ --shell=<shell> ]
                     Name or absolute path for tudo shell.
  [ --shell-home=<path> ]
                     Absolute path for tudo shell home.
  [ --shell-options=<options> ]
                     Additional options to pass to tudo shell.
  [ --shell-post-commands=<commands> ]
                     Bash commands to run after tudo shell for script
                     command type.
  [ --shell-pre-commands=<commands> ]
                     Bash commands to run before tudo shell.
  [ --shell-stdin-string=<string> ]
                     String to pass as stdin to tudo shell for script
                     command type.
  [ --sleep=<seconds> ]
                     Sleep for x seconds before exiting tudo.
  [ --sleep-if-fail ]
                     If '--sleep' option is passed, then only sleep if
                     exit code of tudo does not equal '0'.
  [ --su-path=<path> ]
                     Absolute path for su binary to use instead of
                     searching for it in default search paths.
  [ --su-bin-path-add=0|1 ]
                     Whether to append path to su binary directory to
                     '$PATH' exported for android priority.
  [ --title=<title> ]
                     Title for tudo shell terminal.
  [ --work-dir=<path> ]
                     Absolute path for working directory.


Set log level to '>= DEBUG' to get more info when running tudo command.

Pass '--dry-run' option with log level '>= DEBUG' to see the commands
that will be run without actually executing them.

Visit https://github.com/agnostic-apollo/tudo for more help on how
tudo command works.
TUDO_HELP_EOF

echo $'\n'"Supported interactive shells: \`$TUDO_SUPPORTED_INTERACTIVE_SHELLS\`"
echo $'\n'"Supported script shells: \`$TUDO_SUPPORTED_SCRIPT_SHELLS\`"

}

tudo_show_help_extra() {

    tudo_show_help

    cat <<'TUDO_HELP_EOF' | \
        sed \
            -e "s%[@]TERMUX__LNAME[@]%${TERMUX__LNAME}%g" \
            -e "s%[@]TERMUX_APP__NAME[@]%${TERMUX_APP__NAME}%g"


The 'su' command type drops to an interactive shell as the
'Termux app' user for any of the supported interactive
shells. To drop to a 'bash' shell, just run 'tudo su'. The priority
will be set to termux bin and library paths in '$PATH' and
'$LD_LIBRARY_PATH' variables.
Use the '--shell' option to set the interactive shell to use.


The 'asu' command type is the same as 'su' command type but
instead the priority will be set to android bin and library paths in
'$PATH' and '$LD_LIBRARY_PATH' variables.
Use the '--shell' option to set the interactive shell to use. Only
'/system/bin/sh' shell is allowed on Android '< 7' with '-A' and '-AA'
flags.


The 'path' command type runs a single command as the 'Termux app'
user. You can use it just by running 'tudo <command> [command_args]'
where 'command' is the executable you want to run and 'command_args'
are any optional arguments to it. The 'command' will be run within a
'bash' shell.
The 'command' must be an 'absolute' path to an executable, or
'relative' path from the current working directory to an executable
starting starting with './' or '../' (like './script.sh') or the
executable 'basename' in a directory listed in the final '$PATH'
variable that is to be exported by the 'tudo' command depending on
priority set.
The priority is set based on '-a|-A|-AA' or '-t|-T|-TT' flags, and
if flags are not passed, then the priority for bin paths in '$PATH'
variable is given to termux paths followed by android paths if
executable canonical path is under '$TERMUX__ROOTFS' directory,
otherwise to android paths followed by termux paths.


The 'script' command type takes any script text or path to a script
file for any of the supported script shells referred as 'tudo shell',
and executes the script with any optional arguments with the desired
script shell. This can be done by running the
'tudo -s <core_script> [core_script_args]' command.
The 'core_script' will be considered a 'bash' script by default.
The 'core_script' will be passed to the desired shell using
process substitution or after storing the 'core_script' in a temp file
in a temp directory in 'tudo shell' home
'$TMPDIR/.tudo.temp.XXXXXX/tudo_script__core_script' and passing the path to
the desired shell, where 'XXXXXX' is a randomly generated string.
The method is automatically chosen based on the script shell
capabilities. The '-f' option can be used to force the usage of a
script file. The '-F' option can passed so that the 'core_script'
is considered as a path to script file that should be passed to
'tudo shell' directly instead of considering it as a script text.
Use the '--shell' option to set the script shell to use.
Use the '--post-shell' option to set the interactive shell to use if
'-i' option is passed. Only '/system/bin/sh' shell is allowed on
Android '< 7' with '-A' and '-AA' flags.
The priority is given to termux paths unless '-a|-A|-AA' or
'-t|-T|-TT' flags are passed.


Run "exit" command of your shell to exit interactive shells and return
to the termux shell.
TUDO_HELP_EOF

}

tudo_exit_on_args_error() {
    echo ""
    tudo_show_help || return $?
    tudo_run_pre_exit_commands 1 || return $?
    return 64 # EX__USAGE

}



# If script is sourced, return with success, otherwise call main function.
# - https://stackoverflow.com/a/28776166/14686958
# - https://stackoverflow.com/a/29835459/14686958
if (return 0 2>/dev/null); then
    return 0 # EX__SUCCESS
else
    tudo_main "$@"
    exit $?
fi
