0

I was trying to insert a nested variable as a while loop condition but I can't manage to expand it properly.

print_message() {
    timer=0
    timer_condition="$2"

    while [[ $timer_condition ]]; do
        sleep 1
        timer=$((timer+1))
    done
    echo "$1"
}

print_message 'Hello world, 5 seconds passed...' '$timer != "5"'
print_message 'Hello again, another 10 seconds passed...' '$timer != "10"'

As an example, I created a simple function print_message that accepts 2 arguments: $1 being the message to print and $2 being the condition I want the while loop to test, so that the function could be fed different conditions to display the messages. However, the while loop is testing if $timer_condition itself is true, instead of testing its content. Is there a way to make it work like this?

while [[ $timer != "5" ]]; do

Thank you

  • Agree, not "nested variables". More like an anonymous or lambda function – fpmurphy Nov 18 '17 at 9:49
0

You can use eval:

eval: eval [arg ...]

Execute arguments as a shell command.

Combine ARGs into a single string, use the result as input to the shell, and execute the resulting commands.

Exit Status: Returns exit status of command or success if command is null.

A contrived example just to illustrate:

foo=bar
expr='[[ $foo == bar ]]'
if eval "$expr"; then
  echo 'foo is equal to "bar"'
fi

For your script pass '[[ $timer != 5 ]]' as your param and use

while eval "$timer_condition"; do

Be advised, though, that eval should be used with caution as it is easy to exploit if you're not careful.

  • Thank you for your answer, it fully works. However @fpmurphy1 provided a nice alternative which apparently doesn't pose the problems of eval. Both answers work in the scenario I provided, but yours was able to parse a more complex condition, ie: [[ $(iwconfig wlan0 | grep "ESSID:off") ]]. Would it be possible to use @fpmurphy1 method to test such conditions? From your answer I assume it would be better to avoid the eval if possible. – Radvansky Nov 17 '17 at 10:17
  • The other answer is the better answer when it is applicable but it is applicable only for arithmetic evaluation. Within the double parens you can have integer arithmetic, logical, and bitwise operators (see the Arithmetic Evaluation section of man bash). If this doesn't apply to you you can often use eval safely if careful. You'll have to read up on it and decide what u want to do. (If only you are using/accessing the script then it's not too much of a concern.) Here's a nice site (the page has examples of "good" eval use): mywiki.wooledge.org/BashFAQ/048 – B Layer Nov 17 '17 at 13:50
  • Wish I knew why someone downvoted this. Did I make an error? Or do you just take 'eval is evil' literally? – B Layer Nov 18 '17 at 11:10
1

Here is one way of doing what you want to do:

print_message() {
    timer=0
    timer_condition="$2"

    while (( $timer_condition ))
    do
        sleep 1
        (( timer += 1 ))
    done
    echo "$1"
}

print_message 'Hello world, 5 seconds passed...' 'timer != 5'
print_message 'Hello again, another 10 seconds passed...' 'timer != 10'

~

  • Thank you for your answer, it worked perfectly. Apparently, compared to @b-layer alternative which involves the use of eval , this would be a simpler and more secure approach. However, using @b-layer method I was able to pass a different condition, ie: $(iwconfig wlan0 | grep "ESSID:off") to print the message "Wifi is connected" in case the condition verifies. Is it possible to parse it using your method? – Radvansky Nov 17 '17 at 9:54
  • @Radvansky, you typically will need to use eval in this case. See my example – fpmurphy Nov 18 '17 at 2:32
-1

Suppose you wish the passed condition to be ls -1 | grep demo where demo is an existing file, here is a code snippet that works:

print_message() {
    condition="$2"

    if eval "$condition" > /dev/null
    then
        echo "$1"
    fi
}

print_message 'Found' 'ls -1 | grep demo'
  • Wish I knew why someone downvoted this. Did I make an error? Another 'eval is evil' believer? – fpmurphy Nov 21 '17 at 11:46
  • I think someone downvote because of eval already mentioned in other answer before you posted. – 林果皞 Nov 25 '17 at 0:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.