0

I have something like this in my bash script:

executor="env UNROLL=${u} TB=${tb} ${APP_DIR}/${tp} ${idx} > output.txt" 
$executor

which is not working. I realized that the problem is that it is "escaping" the > character, because if I do:

executor="env UNROLL=${u} TB=${tb} ${APP_DIR}/${tp} ${idx}" 
$executor > output.txt

then it is working properly.

How can I fix it to have everything in a single line?

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
alvarella
  • 81
  • 3
  • 1
    Why do you store the command in a string at all? Use `env UNROLL="${u}" TB="${tb}" "${APP_DIR}/${tp}" "${idx}" > output.txt` directly. If you really have to store the command first, do so be defining a function instead of a string. – Socowi Jun 07 '22 at 23:05
  • Doing that because I am concatenating more things later to "executor" inside a loop. After the loop ends, I execute the resulting "executor" variable. – alvarella Jun 07 '22 at 23:08
  • See https://stackoverflow.com/questions/17529220/why-should-eval-be-avoided-in-bash-and-what-should-i-use-instead – Diego Torres Milano Jun 08 '22 at 00:40
  • Do you need to include the redirect in the dynamically constructed part of the command? If not, you can use an array to construct the command safely; if not... it's more complicated to do this right. In any case, read [BashFAQ #50: "I'm trying to put a command in a variable, but the complex cases always fail!"](http://mywiki.wooledge.org/BashFAQ/050) – Gordon Davisson Jun 08 '22 at 01:31

2 Answers2

1

Storing Bash code in variables is a recipe for (un)escaping bugs. Not to mention how dramatically the script’s behavior can change due to (untrusted) values of expanded variables, especially when combined with eval.

If you want to store a piece of Bash code for later (re)use, use a function:

executor() {
  env UNROLL="${u}" TB="${tb}" "${APP_DIR}/${tp}" "${idx}" > output.txt
}

executor

A more flexible option would be to get the expanded variables and the target file name from the executor function’s arguments, to make it more self-contained and less context-dependent.

executor() {
  local -n args="$1"
  env UNROLL="${args['UNROLL']}" \
      TB="${args['tb']}" \
  "${args['APP_DIR']}/${args['tp']}" "${args['idx']}" > "${args['output']}"
}

declare -A some_executor_arguments=(
  ['UNROLL']='blah_unroll'
  ['tb']='blah_tb'
  ['APP_DIR']='/some/dir/blah'
  ['tp']='some_app'
  ['idx']='5'
  ['output']='output.txt'
)

executor some_executor_arguments
Andrej Podzimek
  • 2,409
  • 9
  • 12
0

I just realized I can do that with eval $executor

alvarella
  • 81
  • 3
  • 2
    `eval` will effectively unescape a level more: `a=x; b='printf "%s" "$a"'; c=$($b); declare -p c; d=$(eval $b); declare -p d` – jhnc Jun 08 '22 at 00:23
  • 2
    `eval` has a well-deserved reputation as a bug magnet (see [this question](https://stackoverflow.com/questions/17529220/why-should-eval-be-avoided-in-bash-and-what-should-i-use-instead)). Short summary: `eval` blurs the line between data and executable code even more than it usually is, leading to all sorts of opportunities for confusion. If you do need to use `eval`, at least double-quote the command string (`eval "$executor"`) to at least limit the confusion. – Gordon Davisson Jun 08 '22 at 01:30