broen
broen

Reputation: 1

Why are my Bash variables getting set late, animate text function

I am writing a Bash function that only works the second time I call it. What it's supposed to do is write a string of characters using an easing function so that the first part of the string gets displayed quickly, then slows down to complete the final words of the string. The caveat is that it should show colors, using tput defined standard terminal colors.

It works great -- on the second run. When it's first run, it shows the escape sequences in the terminal, and not the colors I'm calling for.

Here's my code:

#!/usr/bin/env bash

# Easing function: ease_in_expo
ease_in_expo() {
    local t=$1
    echo "scale=4; if ($t == 0) 0 else 1 * e(10 * ($t - 1))" | bc -l
}

animate_text_with_ease_in_expo() {
    text="$1"
    delay="$2"

    # Regular Colors
    RESET=$(tput sgr0)         # Text Reset
    BLACK=$(tput setaf 0)      # Black
    RED=$(tput setaf 1)        # Red
    GREEN=$(tput setaf 2)      # Green
    YELLOW=$(tput setaf 3)     # Yellow
    BLUE=$(tput setaf 4)       # Blue
    PURPLE=$(tput setaf 5)     # Purple
    CYAN=$(tput setaf 6)       # Cyan
    WHITE=$(tput setaf 7)      # White

    for ((i = 0; i < ${#text}; i++)); do
        progress=$(ease_in_expo "$((i + 1)) / ${#text}")
        sleep "$(echo "$delay * $progress" | bc -l)"

        # Write the string to output
        echo -n "${text:$i:1}"
    done
}

animate_text_with_ease_in_expo "Tutti ${RED}frutti${RESET}, oh ${CYAN}rooty${RESET}; A wop bop b-luma b-lop bam ${GREEN}boom." 0.30

Can ye Bash gurus point me on the right path to getting these color variables loaded on the first run of the function?

Tried defining color variables as ANSI escape sequences, as well as tput setaf's. Tried putting the color definitions in a separate function, calling that function first, and then callback to my animate_text_with_ease_in_expo function. Tried reloading the "text" variable by text=$text after the color definitions are declared.

Output on first run:

Tutti \033[0;31mfrutti, oh \033[0;36mrooty; A wop bop b-luma b-lop bam boom.

Output on second run:

Tutti frutti, oh rooty; A wop bop b-luma b-lop bam boom.

(The above, with appropriate colors added)

The above code is all written into a Bash script called "string-problem.sh". Once entering the directory the script is in, I am calling it via:

. string-problem.sh

Upvotes: 0

Views: 140

Answers (2)

Ed Morton
Ed Morton

Reputation: 204477

As others have pointed out, you can't use a variable in the calling code that's set in the function being called:

$ foo() { local var=hungry; echo "$*"; }

$ foo "I am $var"
I am

$ foo "I am \$var"
I am $var

$ foo 'I am $var'
I am $var

If you're completely in control of the values being passed to that function, though, then you could escape the $ or otherwise stop the shell from expanding the variable when calling the function and then eval the string passed in so the variable isn't expanded upon the function call, it's expanded when evaled inside the function:

$ foo() { local var=hungry; eval echo "$*"; }

$ foo "I am $var"
I am

$ foo "I am \$var"
I am hungry

$ foo 'I am $var'
I am hungry

You should really have your color variables declared outside of your function though so you don't have to call tput 9 times every time you call your function!

Upvotes: 1

KamilCuk
KamilCuk

Reputation: 141758

In short:

func() {
  hello=world
}
func "${hello}"

hello is getting set inside the function. At the time of "${hello}" variable hello is not set, so it expands to nothing.

Just set the variables, once.

# Regular Colors
RESET=$(tput sgr0)         # Text Reset
BLACK=$(tput setaf 0)      # Black
RED=$(tput setaf 1)        # Red
GREEN=$(tput setaf 2)      # Green
YELLOW=$(tput setaf 3)     # Yellow
BLUE=$(tput setaf 4)       # Blue
PURPLE=$(tput setaf 5)     # Purple
CYAN=$(tput setaf 6)       # Cyan
WHITE=$(tput setaf 7)      # White

animate_text_with_ease_in_expo() {
    text="$1"
    delay="$2"
    ...
}

animate_text_with_ease_in_expo "Tutti ${RED}frutti${RESET}, oh ${CYAN}rooty${RESET}; A wop bop b-luma b-lop bam ${GREEN}boom." 0.30

Upvotes: 2

Related Questions