Can zargs run aliases

xargszsh

I have pip install -U aliased as pi. I want to run:

zargs ~/scripts/python/**/requirements.txt -- pi -r

Is there any way to do this?

I also tried this ugly alternative:

zargs ~/scripts/python/**/requirements.txt -- ${aliases[pi]} -r

But it said (eval):2: command not found: pip install -U.

I imagined zargs should be able to do exactly these kinds of stuff, since it is a zsh builtin.

Best Answer

Aliases are csh's poor man's functions. The aliases are not really commands, they are more text substitutions. aliases have their use in more advanced shells that do have functions, as hacking tools for cases where functions can't be used, like in things like:

alias forever='while true; do'

Or

alias fail='{ echo >&2 FAIL; return 1; }'

Which wouldn't work with functions. But here, it's not one of those cases.

alias pi='pip install -U'

Doesn't define a pi command, it defines a pi alias. Here, as it happens, upon expansion, that ends up being turned into the start of a simple command, but aliased are not expanded in all cases where a command is expected. In particular, they are not expanded within functions like zargs here (well, they are, but at the time of the function definition, not invocation, that's were our forever or fail aliases above can be useful). And they are expanded in some contexts where not appropriate (like in pi() { ...; }).

A global alias is not a solution, global aliases are still not commands, they'll still text substitution, but expanded in even more cases.

After a

alias -g pi='pip install -U'

Now, a pi word is expanded wherever it occurs. So for instance, echo pi would output pip install -U.

Here, if you wanted to define a pi command, you would use a function:

pi() pip install -U "$@"

That one would be invoked by zargs.

With your pi simple alias, you could still do:

zargs ~/scripts/python/**/requirements.txt -- ${=aliases[pi]} -r

That is, invoke $IFS-splitting on the definition of the alias. Or going a bit further:

zargs ~/scripts/python/**/requirements.txt -- "${(@Q)${(ze)aliases[pi]}}" -r    

where z does the splitting while taking into account quoting (so for instance echo "foo bar" be split into echo and "foo bar" instead of echo, "foo and bar"), e to perform expansions (like echo $(uname) expanded to echo Linux for instance), Q to remove the quotes, which would give a better approximation in a few more cases.