We could call the above definition of the `greet` command with any number of arguments, including none at all. All of the arguments are collected into `$names` as a list.
Rest parameters can be used together with positional parameters:
```nu
def vip-greet [vip: string, ...names: string] {
for $name in $names {
print $"Hello, ($name)!"
}
print $"And a special welcome to our VIP today, ($vip)!"
}
# $vip $name
# ----- -------------------------
vip-greet Rahul Priya Arjun Anjali Vikram
# => Hello, Priya!
# => Hello, Arjun!
# => Hello, Anjali!
# => Hello, Vikram!
# => And a special welcome to our VIP today, Rahul!
```
To pass a list to a rest parameter, you can use the [spread operator](/book/operators#spread-operator) (`...`). Using the `vip-greet` command definition above:
```nu
let vip = "Tanisha"
let guests = [ Dwayne, Shanice, Jerome ]
vip-greet $vip ...$guests
# => Hello, Dwayne!
# => Hello, Shanice!
# => Hello, Jerome!
# => And a special welcome to our VIP today, Tanisha!
```
### Rest Parameters with Wrapped External Commands
Custom commands defined with `def --wrapped` will collect any unknown flags and arguments into a
rest-parameter which can then be passed, via list-spreading, to an external command. This allows
a custom command to "wrap" and extend the external command while still accepting all of its original
parameters. For example, the external `eza` command displays a directory listing. By default, it displays
a grid arrangement:
```nu
eza commands
# => categories docs README.md
```
We can define a new command `ezal` which will always display a long-listing, adding icons:
```nu
def --wrapped ezal [...rest] {
eza -l ...$rest
}
```
:::note
You could also add `--icons`. We're omitting that in this example simply because those icons don't
display well in this guide.
:::
Notice that `--wrapped` forces any additional parameters into the `rest` parameter, so the command
can be called with any parameter that `eza` supports. Those additional parameters will be expanded via
the list-spreading operation `...$rest`.
```nu
ezal commands
# => drwxr-xr-x - ntd 7 Feb 11:41 categories
# => drwxr-xr-x - ntd 7 Feb 11:41 docs
# => .rw-r--r-- 936 ntd 14 Jun 2024 README.md
ezal -d commands
# => drwxr-xr-x - ntd 14 Jun 2024 commands
```
The custom command can check for certain parameters and change its behavior accordingly. For instance,
when using the `-G` option to force a grid, we can omit passing a `-l` to `eza`:
```nu
def --wrapped ezal [...rest] {
if '-G' in $rest {
eza ...$rest
} else {
eza -l --icons ...$rest
}
}
ezal -G commands
# => categories docs README.md
```
## Pipeline Input-Output Signature
By default, custom commands accept [`<any>` type](./types_of_data.md#any) as pipeline input and likewise can output `<any>` type. But custom commands can also be given explicit signatures to narrow the types allowed.
For example, the signature for [`str stats`](/commands/docs/str_stats.md) looks like this:
```nu
def "str stats" []: string -> record { }
```
Here, `string -> record` defines the allowed types of the _pipeline input and output_ of the command:
- It accepts a `string` as pipeline input
- It outputs a `record`
If there are multiple input/output types, they can be placed within brackets and separated with commas or newlines, as in [`str join`](/commands/docs/str_join.md):
```nu
def "str join" [separator?: string]: [
list -> string
string -> string
] { }
```
This indicates that `str join` can accept either a `list<any>` or a `string` as pipeline input. In either case, it will output a `string`.
Some commands don't accept or require data as pipeline input. In this case, the input type will be `<nothing>`. The same is true for the output type if the command returns `null` (e.g., [`rm`](/commands/docs/rm.md) or [`hide`](/commands/docs/hide.md)):
```nu
def xhide [module: string, members?]: nothing -> nothing { }
```
::: tip Note
The example above is renamed `xhide` so that copying it to the REPL will not shadow the built-in `hide` command.