0

I have a string stored in a variable. Here's the result I want...

cmd="--name=cloudflare-ddns \
--hostname=oznu-cloudflare-ddns \
--env=SUBDOMAIN=private \
--env=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
--env=QEMU_ARCH=x86_64 \
--env=S6_KEEP_ENV=1 \
--env=S6_BEHAVIOUR_IF_STAGE2_FAILS=2 \
--env=CF_API=https://api.cloudflare.com/client/v4 \
--env=RRTYPE=A 
--env='CRON=*/5 *   *   *   *' --env=PROXIED=false \
--env=ZONE=thebiermans.net \
--env=API_KEY=kka \
--network=host \
--restart=always \
--log-driver=db --runtime=runc --detach=true -t oznu/cloudflare-ddns:latest"

How can I store that in a variable so I can execute it?

e.g.

docker run $CMD

I'm missing the right set of escapes here and am getting the wrong output.

Kusalananda
  • 333,661
  • Have you tried to see how it looks to the shell or command? echo -- "$CMD" for example? It might give you some clues what part(s) are wrong. (One thing I see, unless it was a typo in your post here, one line does NOT have a trailing \ escape ...) – C. M. Jun 23 '21 at 10:10
  • 1
  • Storing a command in a string variable is prone to error, and not well advised. Consider using an array or even a function instead – Chris Davies Jun 23 '21 at 10:24
  • @C.M. Yes, echo produces --env='''CRON=/5 * * *''' Not sure what you mean by the trailing escape? – Michael Bierman Jun 23 '21 at 10:27
  • The line --env=RRTYPE=A is missing a \ at the line end in your post, like every other line has. It should not matter here, as they are not needed anyhow due to the outer quotes, but add it if needed (or remove the others) to be consistent and certain. Anyhow, I was trying to help you see it the way the shell does to see if you could see it. Read Stephane's answer if you're still not seeing it. – C. M. Jun 23 '21 at 12:21

1 Answers1

3

For the shell to evaluate shell code stored in a variable, you'd use the eval special builtin command. That's the same as in several other languages:

cmd="--name=cloudflare-ddns \
--hostname=oznu-cloudflare-ddns \
--env=SUBDOMAIN=private \
--env=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
--env=QEMU_ARCH=x86_64 \
--env=S6_KEEP_ENV=1 \
--env=S6_BEHAVIOUR_IF_STAGE2_FAILS=2 \
--env=CF_API=https://api.cloudflare.com/client/v4 \
--env=RRTYPE=A 
--env='CRON=*/5 *   *   *   *' --env=PROXIED=false \
--env=ZONE=thebiermans.net \
--env=API_KEY=kka \
--network=host \
--restart=always \
--log-driver=db --runtime=runc --detach=true -t oznu/cloudflare-ddns:latest"

eval "docker run $cmd"

That assumes the concatenation of "docker run " and the contents of $CMD forms valid code in the syntax of the shell. In that case, the interpretation of that code will result in the execution of the docker command with a list of arguments.

To run a command with a list of arguments stored in a variable, you'd use an array variable:

args=(
  --name=cloudflare-ddns
  --hostname=oznu-cloudflare-ddns
  --env=SUBDOMAIN=private
  --env=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
  --env=QEMU_ARCH=x86_64
  --env=S6_KEEP_ENV=1
  --env=S6_BEHAVIOUR_IF_STAGE2_FAILS=2
  --env=CF_API=https://api.cloudflare.com/client/v4
  --env=RRTYPE=A
  --env='CRON=*/5 *   *   *   *'
  --env=PROXIED=false
  --env=ZONE=thebiermans.net
  --env=API_KEY=kka
  --network=host
  --restart=always
  --log-driver=db --runtime=runc --detach=true 
  -t oznu/cloudflare-ddns:latest
)

docker run "${args[@]}"

In any case, in bash, do not leave parameter expansions unquoted in list contexts as that hardly ever does what you want. Doing that is the split+glob operator, which splits the contents of the variable on characters of $IFS and then performs filename generation on each resulting words. That is totally unrelated to shell syntax tokenisation and syntax parsing which are the parts that recognise and interpret quotes for instance.

  • Thank you that is almost working perfectly. How do I expand variables inside the array? var="hello world" args=( --label=$var ) And, I need single quotes around the var. I've tried ${var} but that didn't work. I've also tried '$var' and that didn't work. – Michael Bierman Jun 23 '21 at 20:27