zsh run a command stored in a variable?
Asked Answered
V

4

29

In a shell script (in .zshrc) I am trying to execute a command that is stored as a string in another variable. Various sources on the web say this is possible, but I'm not getting the behavior i expect. Maybe it's the ~ at the beginning of the command, or maybe it's the use of sudo, I'm not sure. Any ideas? Thanks

function update_install()
{
    # builds up a command as a string...
    local install_cmd="$(make_install_command $@)"
    # At this point the command as a string looks like: "sudo ~some_server/bin/do_install arg1 arg2"
    print "----------------------------------------------------------------------------"
    print "Will update install"
    print "With command: ${install_cmd}"
    print "----------------------------------------------------------------------------"
    echo "trying backticks"
    `${install_cmd}`
    echo "Trying \$()"
    $(${install_cmd})
    echo "Trying \$="
    $=install_cmd
}

Output:

Will update install
With command: sudo ~some_server/bin/do_install arg1 arg2

trying backticks
update_install:9: no such file or directory: sudo ~some_server/bin/do_install arg1 arg2
Trying $()
update_install:11: no such file or directory: sudo ~some_server/bin/do_install arg1 arg2
Trying $=
sudo ~some_server/bin/do_install arg1 arg2: command not found
Virgievirgil answered 2/12, 2012 at 0:21 Comment(1)
you could use zsh -c '${install_cmd}'Roar
F
47

Use eval:

eval ${install_cmd}
Flagrant answered 2/12, 2012 at 0:27 Comment(1)
Nice, simple approach. Thanks!Virgievirgil
P
11

As explained in §3.1 "Why does $var where var="foo bar" not do what I expect?" of the Z-Shell FAQ, you can use the shwordsplit shell option to tell zsh that you want it to split variables up by spaces and treat them as multiple words. That same page also discusses alternatives that you might want to consider.

Petitionary answered 2/12, 2012 at 0:32 Comment(0)
D
1

Previous answers are correct, what worked for me was the below command in zsh

totalin=$(eval echo testing |wc -l)
echo "Total: $totalin"
Daze answered 13/1, 2023 at 19:20 Comment(0)
L
0

I believe you have two problems here - the first is that your install_cmd is being interpreted as a single string, instead of a command (sudo) with 3 arguments.

Your final attempt $=install_cmd actually does solve that problem correctly (though I'd write it as ${=install_cmd} instead), but then you hit your second problem: ~some_server/bin/do_install is not a known command. This is because sudo doesn't interpret the ~ like you intend, for safety reasons; it would need to evaluate its arguments using the shell (or do some special-casing for ~, which is really none of sudo's business), which opens up a whole can of worms that, understandably, sudo does its best to avoid.

That's also why it worked to do eval ${install_cmd} - because that's literally treating the whole string as a thing to be evaluated, possibly containing multiple commands (e.g. if install_cmd contained echo foo; sudo rm -rf / it would be happy to wipe your system).

You have to be the one to decide whether you want install_cmd to allow full shell semantics, including variable interpolation, path expansion, multiple commands, etc. or whether it should just expand the words out and run them as a single command.

Lombardi answered 20/12, 2021 at 17:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.