Home > Blockchain >  Unable to run command in function (shell script)
Unable to run command in function (shell script)

Time:06-04

I have this function in my ~/.zshrc

async () {
    if ! [[ $# -gt 0 ]];then
        echo "Not enough arguments!"
    fi
    local busus="$IFS"
    export IFS=" "
    echo "$* &"
    command "$* &"
    export IFS="$busus"
}

and an alias

alias word='async "libreoffice --writer"'

The echo "$* &" line is used only for debugging. When I run word, libreoffice --writer & is shown on the screen (no extra spaces or newlines), but nothing happens. I also tried executing command libreoffice --writer & and it worked perfectly. (My current shell is zsh) What is wrong?

Thanks

CodePudding user response:

Using "$@" directly is more reliable:

async () { [ "$#" -gt 0 ] && "$@" & }

alias word='async libreoffice --writer'

CodePudding user response:

Usually (especially in bash), the problem is that people aren't using enough double-quotes; in this case, it's the opposite: you're using too many double-quotes. The basic problem is that the command name and each of the arguments to it must be a separate "word" (in shell syntax), but double-quoting something will (usually) make the shell treat it as all one word. Here's a quick demo:

% echo foo
foo
% "echo foo"
zsh: command not found: echo foo

Here, the double-quotes make the shell treat " foo" as part of the command name, rather than as a delimiter and an argument after the command name. Similarly, when you use "$* &", the double-quotes tell the shell to treat the entire thing (including even the ampersand) as a single long word (and pass it as an argument to command). (BTW, the command isn't needed, but isn't causing any harm either.)

The standard way to do this is to use "$@" instead -- here the $@ acts specially within double-quotes, making each argument into a separate word. In zsh, you could omit the double-quotes, but that can cause trouble in other shells so I recommend using them anyway.

Also, don't mess with IFS. You don't need to, and it opens a can of worms that's best left closed. And if there are no arguments, you should return immediately, rather than continuing and trying to run an empty command.

But there's another problem: in the alias, you double-quote "libreoffice --writer", which is going to have pretty much the same effect again. So remove those double-quotes. But keep the single-quotes around the alias, so it'll be defined as a single alias.

So here's my proposed correction:

async () {
    if ! [[ $# -gt 0 ]];then
        echo "Not enough arguments!"
        return 1    # Do not continue if there's no command to run!
    fi
    echo "$* &"    # Here quoting is appropriate, so it's a single argument to echo
    "$@" &
}

alias word='async libreoffice --writer'
  • Related