0

How can i store commands as a variables and execute them randomly in bash?

command1="
   convert -size 2000x1000 xc:none -gravity center \
    -stroke yellow -pointsize 50 -font Courier-BoldOblique -strokewidth 3 -annotate +100+100 "${caption}" \
    -blur 0x25 -level 0%,50% \
    -fill white -stroke none -annotate +100+100 "${caption}" \
    in.jpeg  +swap -gravity center -geometry +0-3 \
    -composite  out.jpeg
"
command2="
   convert -size 2000x1000 xc:none -gravity center \
    -fill white -pointsize 50 -stroke none -annotate +100+100 "${caption}" -channel alpha -evaluate multiply 0.35 -trim +repage \
    in.jpeg  +swap -gravity center -geometry +0-3 \
    -composite  out.jpeg
"

What have i tried

COMMANDS=("command1" "command2")
$(eval $(shuf -n1 -e "${COMMANDS[@]}"))

Desired output is to randomly run any of the two convert commands. How can i get the desired result and where are the things going wrong ??

I have taken hints from -

execute-random-command

how-to-store-a-command-in-a-variable-in-a-shell-script

Thanks in advance for help !!

  • Any reason why you can't turn those commands into functions? Then you could do just "$(shuf -n1 -e command1 command2)". – mosvy Feb 21 at 12:18
  • Two reasons - first they are long and i have many other commands already written so changing each will be just a cumbersome task(these are just examples) – Madhubala Feb 21 at 12:24
  • randomly or on-demand? – ctrl-alt-delor Feb 21 at 12:27
  • That being said, C=("$command1" "$command2"); eval "$(shuf -n1 -e "${C[@]}")" would probably work in your case. Notice the extra $s and the extra "s. – mosvy Feb 21 at 12:29
  • @ctrl-alt-delor run them randomly – Madhubala Feb 21 at 12:30
3

Use a function.

command1(){ 
   convert -size 2000x1000 xc:none -gravity center \
    -stroke yellow -pointsize 50 -font Courier-BoldOblique -strokewidth 3 -annotate +100+100 "${caption}" \
    -blur 0x25 -level 0%,50% \
    -fill white -stroke none -annotate +100+100 "${caption}" \
    in.jpeg  +swap -gravity center -geometry +0-3 \
    -composite  out.jpeg
}

command2() {
   convert -size 2000x1000 xc:none -gravity center \
    -fill white -pointsize 50 -stroke none -annotate +100+100 "${caption}" -channel alpha -evaluate multiply 0.35 -trim +repage \
    in.jpeg  +swap -gravity center -geometry +0-3 \
    -composite  out.jpeg
}

See why Why variables fail when trying to run a command

| improve this answer | |
3

First, this won't work the moment you have whitespace or literal glob characters in the arguments:

command1="convert ... -fill white -stroke none -annotate +100+100 "${caption}" ...

Note how even the syntax highlighting shows that the ${caption} part is not quoted. Quotes don't work inside quotes, i.e. quotes expanded from a parameter are literal, they don't quote again.

See:

Two better options are to store the commands in separate functions, or separate arrays. Sadly, you'll have to come with names for them, you can't have a (numbered) array of functions or an array of arrays.

Then, assuming you have functions or arrays called cmd1 and cmd2, choose one just like you did there, and if you used functions, just run it:

commands=(cmd1 cmd2)
chosen=$(shuf -n1 -e "${commands[@]}")
"$chosen" args...

or if you used an array, you'll have to use a name ref to access it:

commands=(cmd1 cmd2)
declare -n chosen=$(shuf -n1 -e "${commands[@]}")
"${chosen[@]}" args...
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.