# Functions

aux4 provides built-in functions that can be used in your execute instructions to format and transform variable values.

## if

The `if` function allows you to execute instructions based on variable conditions. It uses the `if()` syntax followed by `&&` for the true case and `||` for the false case.

### Check if variable exists

```json
...
  {
    "name": "has-name",
    "execute": [
      "if(name) && echo 'name exists' || echo 'name does not exist'"
    ],
    ...
  }
...
```

```bash
> aux4 has-name
```

```text
name does not exist
```

```bash
> aux4 has-name --name=John
```

```text
name exists
```

### Check if variable is empty

Use `==` with no value after it to check if a variable is empty.

```json
...
  {
    "name": "is-empty",
    "execute": [
      "if(name==) && echo 'name is empty' || echo 'name is not empty'"
    ],
    ...
  }
...
```

### Check if variable has specific value

```json
...
  {
    "name": "is-john",
    "execute": [
      "if(name==John) && echo 'name is John' || echo 'name is not John'"
    ],
    ...
  }
...
```

### Check if variable equals another variable

```json
...
  {
    "name": "is-default",
    "execute": [
      "set:defaultName=John",
      "if(name==$defaultName) && echo 'name is default' || echo 'name is not default'"
    ],
    ...
  }
...
```

### Check if variable is not equal

Use `!=` to check inequality.

```json
...
  {
    "name": "is-not-default",
    "execute": [
      "set:defaultName=John",
      "if(name!=$defaultName) && echo 'name is not default' || echo 'name is default'"
    ],
    ...
  }
...
```

## param

The `param` function formats a variable as a command-line parameter. If the variable has a value, it outputs `--name 'value'`. If the variable is undefined, it outputs nothing.

```json
...
  {
    "name": "print",
    "execute": [
      "log:cmd param(name) param(age)"
    ],
    "help": {
      "variables": [
        {
          "name": "name",
          "text": "the name"
        },
        {
          "name": "age",
          "text": "the age"
        }
      ]
    }
  }
...
```

```bash
> aux4 print --name Joe --age 20
```

```text
cmd --name 'Joe' --age '20'
```

### param with alias

You can specify an alias for the parameter name using `param(variable:alias)`:

```json
...
  {
    "execute": [
      "log:cmd param(name:n) param(age:a)"
    ],
    ...
  }
...
```

```bash
> aux4 print --name Joe --age 20
```

```text
cmd --n 'Joe' --a '20'
```

### param with multiple values

For variables with `multiple: true`, use `param(variable**)` to output each value as a separate parameter:

```json
...
  {
    "execute": [
      "log:cmd param(tag**)"
    ],
    "help": {
      "variables": [
        {
          "name": "tag",
          "text": "tags",
          "multiple": true
        }
      ]
    }
  }
...
```

```bash
> aux4 print --tag first --tag second
```

```text
cmd --tag 'first' --tag 'second'
```

## params

The `params` function formats multiple variables as command-line parameters in a single call:

```json
...
  {
    "execute": [
      "log:cmd params(name, age, city)"
    ],
    ...
  }
...
```

```bash
> aux4 print --name Joe --age 20
```

```text
cmd --name 'Joe' --age '20'
```

Only defined variables are included in the output.

## value

The `value` function outputs just the value without the parameter name:

```json
...
  {
    "execute": [
      "log:cmd value(name)"
    ],
    ...
  }
...
```

```bash
> aux4 print --name Joe
```

```text
cmd 'Joe'
```

### value with multiple values

For variables with `multiple: true`, use `value(variable*)` to get all values as a JSON array:

```json
...
  {
    "execute": [
      "echo value(text*)"
    ],
    "help": {
      "variables": [
        {
          "name": "text",
          "text": "text values",
          "arg": true,
          "multiple": true
        }
      ]
    }
  }
...
```

```bash
> aux4 process abc def
```

```text
["abc","def"]
```

## values

The `values` function outputs multiple values separated by spaces:

```json
...
  {
    "execute": [
      "log:cmd values(name, age, city)"
    ],
    ...
  }
...
```

```bash
> aux4 print --name Joe --age 20
```

```text
cmd 'Joe' '20' ''
```

Unlike `params`, this outputs empty strings for undefined variables.

## object

The `object` function creates a JSON object from the specified variables:

```json
...
  {
    "execute": [
      "log:cmd object(name, age)"
    ],
    "help": {
      "variables": [
        {
          "name": "name",
          "text": "the name"
        },
        {
          "name": "age",
          "text": "the age"
        }
      ]
    }
  }
...
```

```bash
> aux4 print --name Joe --age 20
```

```text
cmd {"age":"20","name":"Joe"}
```

Only defined variables are included in the JSON object. Undefined variables are omitted.

Values are strings by default (`"age":"20"`). Give a variable a [`type`](/variables#type) — `number`, `boolean` or `json` — and `object` emits it typed (`"age":20`), so you rarely need a separate conversion step.

### object with aliases

You can rename fields using `variable:alias` syntax, similar to `param()`:

```json
...
  {
    "execute": [
      "json:cat data.json",
      "log:cmd object(response.name:name, response.age:age, response.address.city:city)"
    ],
    ...
  }
...
```

```bash
> aux4 print
```

```text
cmd {"age":"20","city":"New York","name":"Joe"}
```

Without aliases, nested fields use underscores: `response.name` becomes `response_name`. With aliases, you control the key names.

### object with dynamic fields

You can use a variable to specify which fields to include:

```json
...
  {
    "execute": [
      "log:cmd object($fields)"
    ],
    "help": {
      "variables": [
        {
          "name": "name",
          "text": "the name"
        },
        {
          "name": "age",
          "text": "the age"
        },
        {
          "name": "city",
          "text": "the city"
        },
        {
          "name": "fields",
          "text": "comma-separated list of fields"
        }
      ]
    }
  }
...
```

```bash
> aux4 print --name John --age 23 --city NYC --fields 'name,age'
```

```text
cmd {"age":"23","name":"John"}
```

### object with all parameters

Use `*` to include every current parameter. The parameters are spread directly
into the object (each becomes its own field) — `*` is not a field name. You can
combine it with named fields, e.g. `object(id, *)`.

```json
...
  {
    "execute": [
      "log:object(*)"
    ],
    "help": {
      "variables": [
        { "name": "name", "text": "the name" },
        { "name": "age", "text": "the age" }
      ]
    }
  }
...
```

```bash
> aux4 print --name John --age 23
```

```text
{"age":"23","name":"John"}
```

Note that `*` includes aux4's injected parameters too (such as `aux4HomeDir` and
`packageDir`), so pick named fields instead when you only want specific values.

You can also give the wildcard an alias to nest all parameters under a single key
(as a real object, not a string), and combine it with named fields:

```json
...
  {
    "execute": [
      "log:object(name, *:others)"
    ],
    ...
  }
...
```

```bash
> aux4 print --name John --age 23
```

```text
{"name":"John","others":{"age":"23","name":"John", ...}}
```

## nvl

The `nvl` function returns the first non-null, non-empty value from a list of candidates. It accepts any number of variable names and quoted literal strings as fallbacks.

```json
...
  {
    "name": "show-avatar",
    "execute": [
      "log:avatar=nvl(response.avatar[0].path, defaultAvatar, '/images/default.png')"
    ],
    ...
  }
...
```

It checks each candidate left to right:
1. `response.avatar[0].path` — if the path exists and is non-empty, use it
2. `defaultAvatar` — if this variable is set, use it
3. `'/images/default.png'` — literal fallback (quoted with single or double quotes)

```json
...
  {
    "name": "greet",
    "execute": [
      "log:Hello, nvl(nickname, name, 'stranger')!"
    ],
    "help": {
      "text": "greet someone",
      "variables": [
        {
          "name": "name",
          "text": "the name",
          "default": ""
        },
        {
          "name": "nickname",
          "text": "optional nickname",
          "default": ""
        }
      ]
    }
  }
...
```

```bash
> aux4 greet --nickname Joe
```

```text
Hello, Joe!
```

```bash
> aux4 greet --name John
```

```text
Hello, John!
```

```bash
> aux4 greet
```

```text
Hello, stranger!
```

## path

The `path` function builds an **absolute filesystem path** from one or more segments, resolving it against the current working directory. It replaces the common `case "${x}" in /*) ACFG='${x}';; *) ACFG="$PWD/${x}";; esac` shell idiom.

Segments are separated by `/`:

- a **bare word** is resolved as a variable value
- `..` and `.` are kept as **literal** path segments
- a **quoted** string (single or double quotes) is a literal segment

A relative result is made absolute against the current directory, an already-absolute value is returned unchanged, and an empty result stays empty.

```json
...
  {
    "name": "sync",
    "execute": [
      "log:db=path(db) jobs=path(jobsPath)"
    ],
    "help": {
      "text": "resolve paths",
      "variables": [
        { "name": "db", "text": "database file", "default": "local.db" },
        { "name": "jobsPath", "text": "jobs directory", "default": ".jobs" }
      ]
    }
  }
...
```

```bash
> aux4 sync
```

```text
db=/home/me/project/local.db jobs=/home/me/project/.jobs
```

Multiple segments are joined into a single path. Quote fixed folder names, and use `..` to walk up:

```json
...
  {
    "name": "backup-dir",
    "execute": [
      "log:path(dir/'backups'/name)"
    ],
    "help": {
      "text": "build a backup path",
      "variables": [
        { "name": "dir", "text": "base directory", "default": "data" },
        { "name": "name", "text": "backup name", "default": "shop" }
      ]
    }
  }
...
```

```bash
> aux4 backup-dir
```

```text
/home/me/project/data/backups/shop
```

## arg

The `arg` function accesses positional arguments by index, without needing to define a variable with [`arg: true`](/variables#argument). Position `0` is the command name, `1` is the first argument, and so on. If the index is out of bounds, it returns an empty string.

```json
...
  {
    "name": "greet",
    "execute": [
      "echo arg(0) arg(1)"
    ],
    "help": {
      "text": "greet someone"
    }
  }
...
```

```bash
> aux4 greet hello
```

```text
greet hello
```

You can use `arg` at any position and in any order:

```json
...
  {
    "execute": [
      "echo arg(1) arg(0)"
    ],
    ...
  }
...
```

```bash
> aux4 greet hello
```

```text
hello greet
```

## args

The `args` function returns positional arguments as a JSON array. Use `args(*)` to get all arguments, or specify indices with `args(0,1,2)`.

### args with all arguments

```json
...
  {
    "name": "greet",
    "execute": [
      "echo args(*)"
    ],
    "help": {
      "text": "greet someone"
    }
  }
...
```

```bash
> aux4 greet hello world
```

```text
["greet","hello","world"]
```

### args with specific indices

```json
...
  {
    "execute": [
      "echo args(0,1)"
    ],
    ...
  }
...
```

```bash
> aux4 greet hello
```

```text
["greet","hello"]
```

### args with single index

Even with a single index, `args` always returns a JSON array:

```json
...
  {
    "execute": [
      "echo args(1)"
    ],
    ...
  }
...
```

```bash
> aux4 greet hello
```

```text
["hello"]
```

## exists

The `exists` function checks if a file exists at the path stored in a variable. It resolves to a shell test `[ -f 'path' ]`, so it works with `&&` and `||` for branching.

```json
...
  {
    "name": "use-file",
    "execute": [
      "set:avatar=nvl(response.avatar[0].path, 'default.png')",
      "exists(avatar) && cp ${avatar} output/ || echo file not found"
    ],
    ...
  }
...
```

```bash
> aux4 use-file
```

If `default.png` exists:

```text
(file is copied)
```

If it doesn't:

```text
file not found
```

**Note:** Since `exists()` resolves to a shell test, use shell commands (`echo`, `cp`, etc.) in the `&&`/`||` branches, not aux4 executors like `log:`.

## date, time, datetime, utc and epoch

These functions return the current date and time. With no argument they produce ISO output; pass a format string to customize it.

| Function | Default output | Description |
|----------|----------------|-------------|
| `date()` | `2026-07-21` | ISO date (local) |
| `time()` | `15:04:05` | ISO time (local) |
| `datetime()` | `2026-07-21T15:04:05` | ISO date-time (local, no offset) |
| `utc()` | `2026-07-21T22:04:05Z` | ISO date-time in UTC (Zulu) |
| `epoch()` | `1784665271` | Unix timestamp in seconds |

`datetime()` is local time with no offset; use `utc()` when you need an unambiguous UTC timestamp (for logs, APIs, or cross-machine comparisons). A single call captures one timestamp, so `date()` and `time()` used in the same command stay consistent.

```json
...
  {
    "name": "stamp",
    "execute": [
      "log:built on date() at time()"
    ],
    ...
  }
...
```

```bash
> aux4 stamp
```

```text
built on 2026-07-21 at 15:04:05
```

### Custom formats

`date()`, `time()`, `datetime()` and `utc()` accept a format string built from moment-style tokens.

| Token | Meaning | Token | Meaning |
|-------|---------|-------|---------|
| `YYYY` / `YY` | 4- / 2-digit year | `HH` / `H` | hour 24h, padded / not |
| `MMMM` / `MMM` | month name / abbreviation | `hh` / `h` | hour 12h, padded / not |
| `MM` / `M` | month number, padded / not | `mm` / `m` | minute, padded / not |
| `DD` / `D` | day, padded / not | `ss` / `s` | second, padded / not |
| `dddd` / `ddd` | weekday name / abbreviation | `A` / `a` | AM-PM / am-pm |
| `Z` / `ZZ` | UTC offset `±HH:MM` / `±HHMM` | | |

Doubled tokens are zero-padded, single tokens are not. Any character that isn't a token (like `-`, `:`, `/`, `,` or `T`) is emitted verbatim. To emit token letters literally, wrap them in square brackets — e.g. `date(YYYY-MM-DD[T]HH:mm)` keeps the `T` literal instead of formatting it.

```json
...
  {
    "name": "release",
    "execute": [
      "log:date(MMM, DD, YY) at time(H:mm)"
    ],
    ...
  }
...
```

```bash
> aux4 release
```

```text
Jul, 21, 26 at 15:04
```

### epoch units

`epoch()` returns seconds by default. Pass a unit to change the resolution — `epoch(ms)` for milliseconds or `epoch(ns)` for nanoseconds.

```json
...
  {
    "name": "id",
    "execute": [
      "log:req-epoch(ms)"
    ],
    ...
  }
...
```

```bash
> aux4 id
```

```text
req-1784665271173
```

### data safety

`date()`, `time()`, `datetime()`, `utc()`, `epoch()` and `uuid()` are common names in SQL and other languages, so aux4 resolves them **before** variables are expanded. This means they only act on the text you write in the `execute` array — tokens that arrive at runtime inside a `${variable}`, command output, or a file are left untouched, so data or SQL flowing through a variable is safe. (Formats must be literal too: `date(${fmt})` does not expand the variable, since resolution happens first.)

To keep a call you author yourself literal — for example a database's own `uuid()` or `date(column)` in an inline query — escape it with a backslash, as described in [Escaping functions](#escaping-functions).

## uuid

The `uuid` function generates a UUID. It defaults to **version 7** (time-ordered, RFC 9562), which sorts chronologically and works well as a database key. Pass `uuid(4)` for a classic random version 4. A fresh value is generated for every occurrence, so `uuid() uuid()` yields two distinct identifiers. As with the date functions above, it resolves only in authored `execute` text (not in interpolated data), and a backslash keeps it literal (see [Escaping functions](#escaping-functions)).

| Call | Result |
|------|--------|
| `uuid()` | `019f8661-8b26-7a0c-9d10-501669d7aa67` (v7) |
| `uuid(7)` | version 7 (explicit) |
| `uuid(4)` | `27f0ae22-0961-4f34-8179-64bcf4e39dbc` (v4) |

```json
...
  {
    "name": "new-record",
    "execute": [
      "set:id=uuid()",
      "log:created record ${id}"
    ],
    ...
  }
...
```

```bash
> aux4 new-record
```

```text
created record 019f8661-8b26-7a0c-9d10-501669d7aa67
```

## Escaping functions

Any function call can be kept literal by prefixing it with a backslash. aux4 strips the backslash and emits the call verbatim instead of resolving it — useful when the text is meant for something else, such as a database's own `uuid()` or `date(column)` in an inline query.

```json
...
  {
    "name": "recent",
    "execute": [
      "db query \"SELECT \\uuid(), \\date(created_at) FROM events\""
    ],
    ...
  }
...
```

```text
SELECT uuid(), date(created_at) FROM events
```

This works for every function — `\value(...)`, `\values(...)`, `\param(...)`, `\params(...)`, `\object(...)`, `\nvl(...)`, `\path(...)`, `\if(...)`, `\exists(...)`, `\arg(...)`, `\args(...)`, `\date(...)`, `\time(...)`, `\datetime(...)`, `\utc(...)`, `\epoch(...)` and `\uuid()`.

Because a `.aux4` file is JSON — and JSON also uses the backslash as an escape character — write two backslashes in the file (`\\uuid()`), which becomes `\uuid()` in the resolved command. Note that a quoted string does **not** protect a call: `'uuid()'` still resolves (to an aux4 UUID inside the quotes); only the backslash does.

## Working with Nested Data

All functions support nested data from JSON responses:

```json
...
  {
    "execute": [
      "json:cat data.json",
      "log:cmd params(response.name, response.age, response.address.city)"
    ],
    ...
  }
...
```

Given `data.json`:
```json
{
  "name": "Joe",
  "age": 20,
  "address": {
    "city": "New York",
    "state": "NY"
  }
}
```

```bash
> aux4 print
```

```text
cmd --responseName 'Joe' --responseAge '20' --responseAddressCity 'New York'
```

For `values` with nested data:

```json
...
  {
    "execute": [
      "json:cat data.json",
      "log:cmd values(response.name, response.age, response.address.city)"
    ],
    ...
  }
...
```

```text
cmd 'Joe' '20' 'New York'
```

---

## See Also

- [Variables](/variables)
- [Executors](/executors)
- [Config](/config)
- [Commands](/commands)
- [Testing](/testing)
- [Package Manager](/package-manager)
- [Packaging](/packaging)
- [Docker](/docker)
