Thursday, February 17, 2022

[SOLVED] Check if a file contains a multi-line string in bash

Issue

Background

I am writing a function to append to a file in my $HOME directory called .bash.local.

➡️ .bash.local is sourced via .bash_profile.

However, I want to conditionally append to .bash.local if and only if the file does not already contain the contents of $BASH_CONFIGS.

Things to Keep in Mind

My operating system of choice is MacOS Mojave, thus certain versions of command line applications will be different (e.g. grep on a Mac is BSD grep and not GNU grep).

⚠️ append_to_bash_local()

append_to_bash_local() {
    local LOCAL_BASH_CONFIG_FILE="$HOME"/.bash.local

    declare -r BASH_CONFIGS="
# TOOL_NAME - TOOL_DESCRIPTION.
# Add tool configurations here
"

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # If needed, add the necessary configs in the
    # local shell configuration file.

    if ! grep "^$BASH_CONFIGS" < "$LOCAL_BASH_CONFIG_FILE" &> /dev/null; then
        # this block never runs, even if the contents of $BASH_CONFIG
        # are NOT present in $HOME/.bash.local
    fi

}

Solution

With a little help from @kamil-cuk, I was able to create a more improved version of append_to_bash_local().

⚠️ Please note that because I am on MacOS Mojave & have both BSD-grep & BSD-sed installed by default & neither GNU-grep nor GNU-sed installed, I was forced to find a different solution for truncating new-line characters with the ASCII NUL character. Thankfully, @kamil-cuk had a hacky solution using tr.

Below is the improved version of append_to_bash_local().

⚠️ append_to_bash_local()

  1. First, check if the file does not exist with [ ! -e "$LOCAL_BASH_CONFIG_FILE" ].
  2. Second, use -q with grep to make it silent.
    • ➡️ Make sure to put a ! (not) in the front of grep -q to make sure the status of the output is inverted since we are checking if the file does not contain the contents of $BASH_CONFIGS.
  3. Lastly, use "$(<<<"$BASH_CONFIGS" tr '\n' '\01')" < <(less "$LOCAL_BASH_CONFIG_FILE" | tr '\n' '\01') in order to truncate new-line characters with the ASCII NUL character in both $BASH_CONFIGS & $LOCAL_BASH_CONFIG_FILE.

    append_to_bash_local() {
    
        local LOCAL_BASH_CONFIG_FILE="$HOME"/.bash.local
    
        declare -r BASH_CONFIGS="
        # TOOL_NAME - TOOL_DESCRIPTION.
        # Add tool configurations here
        "
    
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    
        # If needed, add the necessary configs in the
        # local shell configuration file.
    
        if [ ! -e "$LOCAL_BASH_CONFIG_FILE" ] || ! grep -q "$(<<<"$BASH_CONFIGS" tr '\n' '\01')" < <(less "$LOCAL_BASH_CONFIG_FILE" | tr '\n' '\01'); then
            printf '%s\n' "$BASH_CONFIGS" >> "$LOCAL_BASH_CONFIG_FILE"
        fi
    
    }
    


Answered By - Nicholas Adamou
Answer Checked By - Willingham (WPSolving Volunteer)