-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to pass variable length of arguments to other commands #7758
Comments
This seems to work.
This may also work.
|
Thank you so much Darren! The alias one works like a charm! but the custom function still has some problem, it cannot pass the flags down as below. Is there a way to work around this? With this, we could implement a bit more complicated aliases, such as running ansible:
|
ya, i'm not sure why flags don't work. You can do |
yea, my guess is that any flags we use has to be defined as parameter of the custom command and they cannot be captured by rest parameter "...". and this makes implementing pass thru commands really hard.... |
@kubouch did your pass-through PR address this problem or is this a different one? (or maybe it wasn't yours, i can't remember) |
Pass-through signatures work only for |
Thanks Jakub! Is there any plan on adding this feature? This seems to be quite useful for adding helper functions. |
Adding it to the signature is not ideal because you'd lose the type checking on the flags, and also there is no clear way to pass them to commands. One thing that would help is adding a traditional function call syntax, so you could write |
Thank you for a really amazing shell! Another use case where this would be extremely helpful would be something like: # Call ripgrep with the specified arguments and return the results as JSON.
def rgj [...arg: string] {
rg --json $arg | from json -o
} This works fine for positional arguments, but not for keywords. This seems like a pretty natural and reasonable thing to want do. In Python, I could do something like: def rgj(*args, **kwargs):
return rg(*args, json: true, **kwargs)
def rg(*args, **kwargs):
print(args, kwargs)
rgj("foo", bar="baz")
# Prints ('foo',) {'json': True, 'bar': 'baz'} In simple cases, sure, it's probably worth re-declaring and re-documenting all the flags to a command. But I'd really love some simple way to do this. And it's not totally unprecedented, because system commands can already take arbitrary, undocumeted flags. That said, this would require some new machinery to handle a feature analogous to |
I think we should have some kind of "accept raw argument list for this function" syntax. This would allow you to inspect the list as you'd like, and pass on the list of arguments to an external command or other script. My proposal is to add the following syntax (maybe with a different sigil): def foo [ ..*rest ] {
echo $"First arg of rest: ($rest.0)"
# Call the external command with the raw arguments
^external $rest
} So basically the variables are collected in a list of strings, just like with I think adding some kind of One thing that would complicate this feature is mixing normal flags and arguments with this raw args syntax. That is why I think this should not be allowed. You can only accept all the raw args, or let nu parse flags and args, but you can't do both. This also means you cannot define different commands with the same prefix like |
The problem with kwargs is that you lose the benefits of our signature system: Type checking, completions, docs, etc. If you plan to use kwargs in the signature, you can just as well use a record. It can also create hard-to-follow APIs We're not very keen on adding this at the moment. The actual problem here is how to pass flags along, for example:
One solution (not the only one) is to allow alternative syntax for command call, similar to classic function call syntax:
or shorter, if the passed flag name is same as the expected flag name:
|
My main use case isn't to use this with nu functions but with external commands. They can accept the $rest list just fine. Currently it just isn't possible to create wrapper scripts for external commands with nu. This is a big use case for shells, so this should also be possible in nu shell. As for applying an internal function with a list of arguments, I briefly talked about this in another issue: #8751. The idea being you add a lisp-style |
Just to be clear: it should be possible to forward any flags, not just flags you have defined for your function |
(Ooops, I realized I commented on this issue before already with the same message.) That's a good point. If we reduce the problem only on externals, it becomes simpler as externals only need strings. We have an existing concept that's used in
would parse/highlight the I don't understand the |
Yea it's not really applicable to this issue but I'll give a quick example on how it could be used: let args = if test {
["--foo", "bar"]
} else {
["--foo", "baz"]
}
# imagine this has multiple such checks, building up an $args list
# now run the internal-fn with the collected args in subcommand
let args = ["subcommand"] + $args
apply internal-fn $args It may not be the case that this is possible with the current architecture, as the subcommand would be defined as |
I think your idea of having |
Yeah, constructing commands like that dynamically is currently not possible, so the |
But yeah, the |
Any updates on this? In bash I might do something like this: function wrapped_cmd {
cmd --arg1=2 "$@" --output=~/.cache
} which lets me do wrapped_cmd -a 1 -b 2 file.txt
# => cmd --arg1=2 -a 1 -b 2 file.txt --output=~/.cache It's really useful for creating more complex aliases, especially if I just want to wrap some external command that I don't know all the current (and future) flags for. Curious if there's something that would let me do this in nushell. |
You can now use the spread operator: def lsl [...x] { ls -l ...$x } |
In case anyone stumbles upon this issue as I did after trying a few suggested solutions, the correct (as of v0.93) way of doing this is using the Only works with external commands. An example if you'd want to shadow bat: alias _bat = bat
def --wrapped bat [...rest] {
_bat -p ...$rest
}
bat -n It should show the output of both -p and -n applied. |
I just used a combination of applying the ...rest parameter attribute to all the options and the |
|
Yeah, I'm sorry for my mistake. I used |
Question
Hi, I really like nushell and would like to use it for my daily shell, but I met some problems when I am trying to create some aliases in nushell, specifically - how to create an alias that accepts variable parameters. Could anyone help me take a look?
It might be a dumb question, but I am kinda stuck. I did some searches and have tried several ways below to do it, but none of them works.
First, I tried to use
alias
keyword (https://www.nushell.sh/book/aliases.html#aliases):Then I have tried to use custom commands with rest parameters (https://www.nushell.sh/book/custom_commands.html#rest-parameters):
With some searches, I found a few threads discussing similar things (e.g. #1716), so I have also tried the syntax there, but it looks like the syntax is already changed:
So I am wondering what would be the right way to do it and is there any doc for this?
Really appreciate for the help in advance!
Additional context and details
No response
The text was updated successfully, but these errors were encountered: