Home > Enterprise >  how do I execute a variable, in zsh?
how do I execute a variable, in zsh?

Time:09-01

I have a very basic function.

t() {
[[ -f ./terragrunt.hcl ]] && local exe=terragrunt
[[ ! -f ./terragrunt.hcl ]] && local exe=terraform

[[ ! $exe ]] && echo -e "\033[31;1m[ERROR]\033[0m Can't figure out what to run. Please run manually"
local cmd="$exe $@"
[[ $DEBUG ]] && echo -e "\033[34;1m[DEBUG]\033[0m executable is $exe.
Args are $@
Command to be run: $cmd"
$cmd
}

However, when I run it like t outputs It returns t:9: command not found: terraform output

I can run terraform output and get the proper output.

I have tried eval and return as well, neither work.

CodePudding user response:

Don't use cmd at all; there's no good way to correctly encode a valid command line in a single string.

t() {
    [[ -f ./terragrunt.hcl ]] && local exe=terragrunt
    [[ ! -f ./terragrunt.hcl ]] && local exe=terraform
    
    [[ ! $exe ]] && echo -e "\033[31;1m[ERROR]\033[0m Can't figure out what to run. Please run manually"
    [[ $DEBUG ]] && echo -e "\033[34;1m[DEBUG]\033[0m executable is $exe.
    Args are $@
    Command to be run: $exe $@"

    "$exe" "$@"
}

Constructing an accurate string representation of the command resulting from an arbitrary value of $@ is non-trivial and barely worth doing.

CodePudding user response:

The problem is that you're doing:

local cmd="$exe $@"

This constucts a single string out of $exe and $@, and when you use $cmd it will try to run that string as a command, including spaces, as if you had typed "terraform output" (which will try to look up /bin/terraform output) rather than terraform output. Hence your error:

t:9: command not found: terraform output

The easiest way to deal with this in zsh is to use arrays:

local cmd=($exe $@)
$cmd

CodePudding user response:

Word splitting occurs before parameter expansion in zsh. In your case, you would have to use

${(z)cmd}

to tell zsh that you want to have an extra round of word splitting after the expansion. However, this will word-split everything inside cmd. I you want to avoid this, make cmd an array , where the command itself is the first element and each subsequent element is a an argument, and invoke it as

$cmd[@]
  • Related