4

As part of an error handling function, I need to report the currently executing command when an error is trapped. The bash $BASH_COMMAND string contains the command, but with nested non-expanded variables. I would like to avoid using eval if there is a better way.

Given these input variables:

path1="a/a/a"
path2="b/b/b"
BASH_COMMAND='mycommand "$path1" $path2'

Produce this output variable:

expanded='mycommand a/a/a b/b/b"

This works with eval, but I am concerned this may be unsafe:

expanded=$(eval echo "$BASH_COMMAND")

EDIT: as chepner explained in the comment below, this question is not answered by Bash expand variable in a variable because the string must be parsed and may contain multiple nested variables.

Community
  • 1
  • 1
Steve
  • 1,250
  • 11
  • 25
  • 2
    That question assumes you have just the name in the variable, not a string with one or more parameter expansions embedded in it. For this problem, you'd need to do some additional non-trivial parsing to isolate the parameter names first. – chepner Dec 07 '15 at 22:23
  • What about if you have spaces in your variables? How should quoting be handled then? – Mr. Llama Dec 08 '15 at 18:28
  • 1
    Very, *very* nontrivial. I've seen POSIX sh parsers available (albeit none of them written in shell), but I've never seen a fully complete parser for bash syntax available in bash. – Charles Duffy Dec 08 '15 at 18:30
  • 1
    Frankly, it's a lot more feasible to just dump all variables defined and let the person doing the debugging sort out which ones are pertinent. – Charles Duffy Dec 08 '15 at 18:30
  • 1
    ...and the easy approaches will execute`$(command-substitutions)` and the like, which are inherently side-effecting operations. – Charles Duffy Dec 08 '15 at 18:33
  • Looks like bash doesn't support what you want. `set -x` and parse stderr? I know, horrible... – Karoly Horvath Dec 08 '15 at 18:49
  • note: I foolishly downvoted your question the first time I saw it, because I didn't get it (perhaps add an actual usage example, I doubt it's a common known feature). please edit the Q so I can upvote. thx. – Karoly Horvath Dec 08 '15 at 18:50
  • 1
    @KarolyHorvath, one can do better than parsing stderr -- with bash 4 or later, you can redirect `set -x` output to an arbitrary file descriptor with `BASH_XTRACEFD`, so the content can be directed to an arbitrary location or process. – Charles Duffy Dec 08 '15 at 19:52
  • Thx. Nice topic! @ElliottFrisch: can you remove your close vote? – Karoly Horvath Dec 08 '15 at 20:04
  • 1
    I'm also looking for a nice solution. `eval echo "${BASH_COMMAND}"` works for expanding variable but strips quotes :-( – pLumo Apr 13 '17 at 07:42
  • If you want to evaluate something, you have to use `eval`. If you fear `eval`, you should also fear any alternative doing the same. – ceving Nov 29 '21 at 08:17

1 Answers1

0

You can create a new file with the command and source that file then remove it. Here is a working script:

path1="a/a/a"
path2="b/b/b"

mycommand() {
  echo $@
}

MY_COMMAND='mycommand "$path1" $path2'

echo "$MY_COMMAND" > ./temp.sh
source ./temp.sh
rm ./temp.sh

BTW, I renamed BASH_COMMAND to MY_COMMAND because it is an internal environment variable containing the currently executed command with its arguments. Instead of writing to temp.sh, you can also generate a file using RANDOM inside the /tmp/ directory:

path1="a/a/a"
path2="b/b/b"

mycommand() {
  echo $@
}

MY_COMMAND='mycommand "$path1" $path2'
RAND_NUM=$RANDOM

echo "$MY_COMMAND" > /tmp/temp-$RAND_NUM.sh
source /tmp/temp-$RAND_NUM.sh
Saiansh Singh
  • 583
  • 5
  • 16