0

I have a variable that has a command that I want to run. It has a bunch of double-quotes. when I echo it, it looks beautiful.

I can copy-paste it and run it just fine.

I tried simply $cmd, but it doesn't work. I get an error as if the command is malformed.

I then tried running it via eval "$cmd" or similarly, bash -c "$cmd", which works, but I don't get any output until the command is done running.

Example with bash -c "$cmd":

This runs the command, BUT I don't get any output until the command is done running, which sucks and I'm trying to fix that:

cmd="docker run -v \"$PROJECT_DIR\":\"$PROJECT_DIR\" \
    -v \"$PPI_ROOT_DIR/utilities/build_deploy/terraform/modules/\":/ppi_modules \
    --workdir \"$PROJECT_DIR/terraform\" \
    --env TF_VAR_aws_account_id=$AWS_ACCOUNT_ID \
    --env TF_VAR_environment=${ENVIRONMENT} \
    --env TF_VAR_region=${AWS_DEFAULT_REGION:-us-west-2} \
    ${OPTIONAL_AWS_ENV_VARS} \
    ${CUSTOM_TF_VARS} \
    ${TERRAFORM_BASE_IMAGE} \
    init --plugin-dir=/.terraform/providers \
        -reconfigure \
        -backend-config=\"bucket=${AWS_ACCOUNT_ID}-tf-remote-state\" \
        -backend-config=\"key=${ENVIRONMENT}/${PROJECT_NAME}\" \
        -backend-config=\"region=us-west-2\" \
        -backend-config=\"dynamodb_table=terraform-locks\" \
        -backend=true"
# command output looks good. I can copy and paste it and run it my terminal too.
echo $cmd
# Running the command via bash works, 
# but I don't get the output until the command is done running, 
# which is what I'm trying to fix:
bash -c "$cmd"

Here is an example using bash array. It prints it to screen perfectly, but just like running it like $cmd, it throws an error as if the command is malformed:

cmd=(docker run -v \"$PROJECT_DIR\":\"$PROJECT_DIR\" \
    -v \"$PPI_ROOT_DIR/utilities/build_deploy/terraform/modules/\":/ppi_modules \
    --workdir \"$PROJECT_DIR/terraform\" \
    --env TF_VAR_aws_account_id=$AWS_ACCOUNT_ID \
    --env TF_VAR_environment=${ENVIRONMENT} \
    --env TF_VAR_region=${AWS_DEFAULT_REGION:-us-west-2} \
    ${OPTIONAL_AWS_ENV_VARS} \
    ${CUSTOM_TF_VARS} \
    ${TERRAFORM_BASE_IMAGE} \
    init --plugin-dir=/.terraform/providers \
        -reconfigure \
        -backend-config=\"bucket=${AWS_ACCOUNT_ID}-tf-remote-state\" \
        -backend-config=\"key=${ENVIRONMENT}/${PROJECT_NAME}\" \
        -backend-config=\"region=us-west-2\" \
        -backend-config=\"dynamodb_table=terraform-locks\" \
        -backend=true)

echo "${cmd[@]}"

"${cmd[@]}"

How can I execute a bash variable that has double-quotes, but run it so I get the output in realtime, just as if I executed via $cmd (which doesn't work)

Similar to these questions, but my question is to run it AND get the output in realtime:

Execute command containing quotes from shell variable

Bash inserting quotes into string before execution

bash script execute command with double quotes, single quotes and spaces

grayaii
  • 2,241
  • 7
  • 31
  • 47
  • I could not find a pipe in your command, but it may solve it anyway: https://unix.stackexchange.com/questions/25372/turn-off-buffering-in-pipe. Looks like something is buffered, see stdbuf. This behaviour is not typical, I tried to reproduce it using other commands (ex. echo and sleep) and I get the output as it happens. – Nic3500 May 22 '22 at 19:12
  • I suspect there's something else causing this (or at least involved). If you run the command directly, without storing it in a variable first (but otherwise in the identical environment), do you get output as it runs, or does it also wait until the end this way? – Gordon Davisson May 22 '22 at 22:51
  • Isn't `exec $cmd` working? – Julien B. May 23 '22 at 04:07
  • @Philippe you were right. Those backslash quotes were the issue. I thought I tried that combination, but apparently not. Feel free to write it as an answer and I'll mark it as the solution – grayaii May 23 '22 at 21:28
  • 1
    Storing code inside variables is a security-impacting antipattern in the first place. See [BashFAQ #50](https://mywiki.wooledge.org/BashFAQ/050) -- functions or arrays should be used for this purpose instead. – Charles Duffy May 23 '22 at 21:58
  • 1
    ...and `echo $cmd` is likewise itself buggy; see [I just assigned a variable, but `echo $variable` shows something else!](https://stackoverflow.com/questions/29378566/i-just-assigned-a-variable-but-echo-variable-shows-something-else) – Charles Duffy May 23 '22 at 22:00
  • 1
    ...as for the array version, the problem is that you're using literal quotes (caused by the backslashes) where you should be using syntactic ones. Even then, `echo "${cmd[@]}"` is useless for debugging (because `cmd=( "two words" )` and `cmd=( "two" "words" )` both look the same when you do `echo "${cmd[@]}"`, leaving quoting issues completely invisible); use `echo "${cmd[@]@Q}"` instead if you're targeting bash 5.0 or newer (or, even better, `printf '%s\n' "${cmd[@]@Q}"` to avoid some of `echo`'s more obscure issues). – Charles Duffy May 23 '22 at 22:01
  • 1
    ...you can also use `set -x` to enable trace logging, which makes the distinction between literal and syntactic quotes visible in much the same way. – Charles Duffy May 23 '22 at 22:04

1 Answers1

2

In your array version, double quotes escaped by a backslash become part of the arguments, which is not intended.

So removing backslashes should fix the issue.

Philippe
  • 20,025
  • 2
  • 23
  • 32