0

My script has a function do_command() that prints a command and then executes it. I want to put my commands in a bash array of strings, and then print _ execute them with this function. But when I try this with an if statement it fails. This is the script:

#!/bin/bash

do_command () { echo "$@"; $@; }

comms=( "wget -O test http://speedtest.ftp.otenet.gr/files/test100k.db" # just a download test
"/bin/bash -c 'if [ -f test ]; then mv test test.old; fi'" # replace previous test
);

for comm in "${comms[@]}"; do do_command "$comm"; done

I have tried different combinations of single + double quotes, putting the bare if-statement there or as an argument of /bin/bash, but have not yet found a way to do it. With this particular combination, the output from the last line is:

/bin/bash -c 'if [ -f test ]; then mv test test.old; fi'
[: -c: line 1: unexpected EOF while looking for matching `''
[: -c: line 2: syntax error: unexpected end of file

But if I copy and paste the printed line to the prompt, it executes without an error.

Is there a way to read an if-statement from a file/array and then execute it in a script?

1 Answers1

1

That /bin/bash -c 'if [ -f test ]; then mv test test.old; fi' will get word-split (at the unquoted $@) as /bin/bash, -c, 'if, [, ... The argument to -c, the commands given to Bash to execute is that 'if. It has an unbalanced quote, so it produces a syntax error. (The rest of the args would go to the positional parameters of the executed commands.)

It won't work with "$@" quoted either, as you only have one argument to the script so it'd all stay a single string.

See: How can we run a command stored in a variable?

If you want to store commands like that, you'll have to run them with eval:

execute() {
    printf "executing {{ %s }}\n" "$1"
    eval "$1"
}
cmds=("echo foo bar"
      "if true; then echo yes; fi"
      "foo=123; echo \"\$foo\""
      'echo "$(date)"'
      "echo \"what's \$foo now?\""
     )
for c in "${cmds[@]}"; do
    execute "$c"
done

Though with complex commands, you'll have the usual quoting hell issues.

You might consider putting the commands in functions instead, and using set -x to print what happens, but the output would be different.

ilkkachu
  • 138,973