1

When posting this question originally, I totally misworded it, obtaining another, reasonable but different question, which was correctly answered here.

The following is the correct version of the question I originally wanted to ask.

In one of my Bash scripts, there's a point where I have a variable SCRIPT which contains the /path/to/an/exe which, when executed, outputs a line to be executed.

What my script ultimately needs to do, is executing that line to be executed. Therefore the last line of the script is

$($SCRIPT)

so that $SCRIPT is expanded to /path/to/an/exe, and $(/path/to/an/exe) executes the executable and gives back the line to be executed, which is then executed.

However, running shellcheck on the script generates this error:

In setscreens.sh line 7:
$($SCRIPT)
^--------^ SC2091: Remove surrounding $() to avoid executing output.

For more information:
  https://www.shellcheck.net/wiki/SC2091 -- Remove surrounding $() to avoid e...

Is there a way I can rewrite that $($SCRIPT) in a more appropriate way? eval does not seem to be of much help here.

Enlico
  • 23,259
  • 6
  • 48
  • 102
  • 1
    Did you try it? shellcheck is great and highly recommended, but can only warn you against specific syntax error and general bad practice. You have a case where `$( )` is appropriate, so go ahead and try it ;-! Good luck! – shellter Aug 30 '20 at 17:23
  • Tried and works, yes. With this question I'm just trying to understand if there's an inherently better way to do the same thing. – Enlico Aug 30 '20 at 17:33
  • Refers to initial question: https://stackoverflow.com/q/63658986/7939871 – Léa Gris Aug 30 '20 at 18:04

4 Answers4

3

You can make it simple by setting the command to be executed as a positional argument in your shell and execute it from the command line

set -- "$SCRIPT"

and now run the result that is obtained by expansion of SCRIPT, by doing below on command-line.

"$@"

This works in case your output from SCRIPT contains multiple words e.g. custom flags that needs to be run. Since this is run in your current interactive shell, ensure the command to be run is not vulnerable to code injection. You could take one step of caution and run your command within a sub-shell, to not let your parent environment be affected by doing ( "$@" ; )

Inian
  • 80,270
  • 14
  • 142
  • 161
  • 2
    While this is a good syntax to keep in mind for very useful and sometimes needed with POSIX shell for word splitting, array data handling and dynamic command processing; It is still an unusual coding practice to execute the output of another command. `# shellcheck disable=SC # reason` is a chance to clarify your intention and finally make the statement implication more straightforward. – Léa Gris Aug 30 '20 at 17:56
3

If the script outputs a shell command line to execute, the correct way to do that is:

eval "$("$SCRIPT")"

$($SCRIPT) would only happen to work if the command can be completely evaluated using nothing but word splitting and pathname expansion, which is generally a rare situation. If the program instead outputs e.g. grep "Hello World" or cmd > file.txt then you will need eval or equivalent.

that other guy
  • 116,971
  • 11
  • 170
  • 194
2

Or use shellcheck disable=SCnnnn to disable the warning and take the occasion to comment on the explicit intention, rather than evade the detection by cloaking behind an intermediate variable or arguments array.

#!/usr/bin/env bash

# shellcheck disable=SC2091 # Intentional execution of the output
"$("$SCRIPT")"

By disabling shellcheck with a comment, it clarifies the intent and tells the questionable code is not an error, but an informed implementation design choice.

Léa Gris
  • 17,497
  • 4
  • 32
  • 41
  • In general, I agree that comments to disable warnings while explaining the intentions is preferrable to strange workaround, however `eval` seems a valid, and I'd also say self-documenting, solution. – Enlico Oct 03 '20 at 09:56
1

you can do it in 2 steps

command_from_SCRIPT=$($SCRIPT)
$command_from_SCRIPT

and it's clean in shellcheck

Cyril Jouve
  • 990
  • 5
  • 15