1

im having trouble getting a dynamically generated shell function to evaluate properly (by evaluate i mean "eval" command)

this is the desired statement to be evaluated when ran (except the output will be executed/evaluated by eval)

$ package_check_repo_printf
if [ $(printf '%s\n' "found ${treelistnew0[@]}" | grep -i -e ^"$1") ]
    then
    url=$POOL0$1
    ftp=$ftpPOOL0$1
    echo $1 found in $POOL0
elif [ $(printf '%s\n' "found ${treelistnew1[@]}" | grep -i -e ^"$1") ]
    then
    url=$POOL1$1
    ftp=$ftpPOOL1$1
    echo $1 found in $POOL1
else
    echo $1 not found
fi

and its code:

package_check_repo_printf() {
for i in ${!REPOS[@]}
    do
if [[ $ifgen == "" ]]
then
printf '%s' "if [ \$(printf '%s\n' \"found \${treelistnew0[@]}\" | grep -i -e ^\"\$1\") ]
    then
    url=\$POOL0\$1
    ftp=\$ftpPOOL0\$1
    echo \$1 found in \$POOL0
"
ifgen=gen
else
printf '%s' "elif [ \$(printf '%s\n' \"found \${treelistnew$i[@]}\" | grep -i -e ^\"\$1\") ]
    then
    url=\$POOL$i\$1
    ftp=\$ftpPOOL$i\$1
    echo \$1 found in \$POOL$i
"
fi
done
printf '%s' "else
    echo \$1 not found
fi"
}

when i replace all the printf '%s' with eval i get this

package_check_repo_eval() {
set -v
for i in ${!REPOS[@]}
    do
if [[ $ifgen == "" ]]
then
eval "if [ \$(printf '%s\n' \"found \${treelistnew0[@]}\" | grep -i -e ^\"\$1\") ]
    then
    url=\$POOL0\$1
    ftp=\$ftpPOOL0\$1
    echo \$1 found in \$POOL0
"
ifgen=gen
else
eval "elif [ \$(printf '%s\n' \"found \${treelistnew$i[@]}\" | grep -i -e ^\"\$1\") ]
    then
    url=\$POOL$i\$1
    ftp=\$ftpPOOL$i\$1
    echo \$1 found in \$POOL$i
"
fi
done
eval "else
    echo \$1 not found
fi"
set +v
}

and its output ( note for this to be CORRECT it should look the same as the package_check_repo_printf's output as set -v will echo the lines executed as printf is not printing the lines) :

[chakra@chakra-pc UPM]$ unset ifgen
[chakra@chakra-pc UPM]$ package_check_repo_eval
if [ $(printf '%s\n' "found ${treelistnew0[@]}" | grep -i -e ^"$1") ]
    then
    url=$POOL0$1
    ftp=$ftpPOOL0$1
    echo $1 found in $POOL0
bash: syntax error: unexpected end of file
elif [ $(printf '%s\n' "found ${treelistnew1[@]}" | grep -i -e ^"$1") ]
bash: syntax error near unexpected token `elif'
else
bash: syntax error near unexpected token `else'
[chakra@chakra-pc UPM]$

how would i get this to work correctly?

note: just to be clear, my goal is to make this function EVAL based instead of PRINTF based

a better example would be this (although im not sure if this is acomplishable another way but still, it generates a usable if elif else statement)

dogs=(1 2 3)
dog=(pink blue white)
colour=(pink black white)
dogs_printf() {
unset ifgen
for i in ${!dogs[@]}
    do
if [[ $ifgen == "" ]]
then
printf '%s' "for i in \${!dogs[@]}
do
if [[ \${dog[i]} == \"\${colour[$i]}\" ]]
    then
    echo dog$i is \"\${colour[$i]}\"
"
ifgen=gen
else
printf '%s' "elif [[ \${dog[i]} == \"\${colour[$i]}\" ]]
    then
    echo dog$i is \"\${colour[$i]}\"
"
fi
done
printf '%s' "else
    echo dog \$i not found
fi
done
"
}
dogs_printf

its output:

[chakra@chakra-pc UPM]$ dogs=(1 2 3)
[chakra@chakra-pc UPM]$ dog=(pink blue white)
[chakra@chakra-pc UPM]$ colour=(pink black white)
[chakra@chakra-pc UPM]$ dogs_printf() {
> unset ifgen
> for i in ${!dogs[@]}
>     do
> if [[ $ifgen == "" ]]
> then
> printf '%s' "for i in \${!dogs[@]}
> do
> if [[ \${dog[i]} == \"\${colour[$i]}\" ]]
>     then
>     echo dog$i is \"\${colour[$i]}\"
> "
> ifgen=gen
> else
> printf '%s' "elif [[ \${dog[i]} == \"\${colour[$i]}\" ]]
>     then
>     echo dog$i is \"\${colour[$i]}\"
> "
> fi
> done
> printf '%s' "else
>     echo dog \$i not found
> fi
> done
> "
> }
[chakra@chakra-pc UPM]$ dogs_printf
for i in ${!dogs[@]}
do
if [[ ${dog[i]} == "${colour[0]}" ]]
    then
    echo dog0 is "${colour[0]}"
elif [[ ${dog[i]} == "${colour[1]}" ]]
    then
    echo dog1 is "${colour[1]}"
elif [[ ${dog[i]} == "${colour[2]}" ]]
    then
    echo dog2 is "${colour[2]}"
else
    echo dog $i not found
fi
done
[chakra@chakra-pc UPM]$ for i in ${!dogs[@]}
> do
> if [[ ${dog[i]} == "${colour[0]}" ]]
>     then
>     echo dog0 is "${colour[0]}"
> elif [[ ${dog[i]} == "${colour[1]}" ]]
>     then
>     echo dog1 is "${colour[1]}"
> elif [[ ${dog[i]} == "${colour[2]}" ]]
>     then
>     echo dog2 is "${colour[2]}"
> else
>     echo dog $i not found
> fi
> done
dog0 is pink
dog 1 not found
dog2 is white
[chakra@chakra-pc UPM]$ 
15
  • 1
    You might want to simplify your example a little bit, i.e. try to come up with a minimal example that produces the same problem. Maybe I'm not understanding your question, but it looks like there's a lot of superfluous stuff here.
    – igal
    Commented Oct 17, 2017 at 15:40
  • 1
    I really hope this is just a toy problem you created for fun, because otherwise what you're doing here is utterly horrifying. Commented Oct 17, 2017 at 15:42
  • reduced it to problem only, got rid of the examples even though they may provide help
    – Clark Kent
    Commented Oct 17, 2017 at 15:49
  • and unix.stackexchange.com/users/74972/parthian-shot how would you improve the script since it is "utterly horrifying"
    – Clark Kent
    Commented Oct 17, 2017 at 15:53
  • @ClarkKent What I meant was more along the lines of removing everything you possibly can while still producing the same error, e.g. remove all of the extraneous variables and function calls.
    – igal
    Commented Oct 17, 2017 at 16:03

1 Answer 1

0

It's not entirely clear to me what you're asking, but here is a very simple example that addresses the question in the title (how to evaluate a dynamically generated if-statement in the shell):

#!/bin/bash

# eval_dynamic_if_then

# Get a command to test from the user
COMMAND="$*"

# Construct an if-then statement using the user
# supplied command and save it to a variable
read -r -d '' IF_THEN <<HEREDOC
if eval "${COMMAND}"; then
  echo "Command successful!"
else
  echo "Command NOT successful!"
fi
HEREDOC

# Evaluate the command
eval "${IF_THEN}"

Here is an example invocation of this script:

./eval_dynamic_if_then true

This results in the following output:

Command successful!

Alternatively:

./dynamic_if_then false

produces:

Command NOT successful!

Since you're also experimenting with printf, here is an adaption which only prints the command instead of evaluating it:

#!/bin/bash

# print_dynamic_if_then

# Get a command to test from the user
COMMAND="$*"

# Construct an if-then statement using the user
# supplied command and save it to a variable
read -r -d '' IF_THEN <<HEREDOC
if eval "${COMMAND}"; then
  echo "Command successful!"
else
  echo "Command NOT successful!"
fi
HEREDOC

# Print the command
printf "${IF_THEN}"

Now to evaluate the output of this script you would do something like the following:

eval "$(print_dynamic_if_then true)"

Notice that the substitution is quoted, e.g. the following won't work:

eval $(print_dynamic_if_then true)

This results in the following error message:

-bash: syntax error: unexpected end of file

Looking at your original example, it looks like you wanted to replace printf statements with eval statements in places where the argument string being passed in was only a code-fragment and not a complete shell statement. The solution to that particular problem is to generate the entire statement to be executed before passing it to the eval command.

I'd also like to echo the comments of other users who recommended against this approach. If I were you I would consider thinking about a way to accomplish your ultimate goal without relying on the eval command.

6
  • made my question a bit more clear (hopefully) if not then tell me what you do not understand
    – Clark Kent
    Commented Oct 17, 2017 at 16:07
  • Can you remove everything having to do with checking repositories and replace it with some simple boiler plate?
    – igal
    Commented Oct 17, 2017 at 16:11
  • I've updated my answer to include a comparison to the printf approach you seem to be using in the body of your post.
    – igal
    Commented Oct 17, 2017 at 16:20
  • i tried that but i got the same result as you even if i quoted the printf function
    – Clark Kent
    Commented Oct 17, 2017 at 16:24
  • i made a more usable example
    – Clark Kent
    Commented Oct 17, 2017 at 16:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .