aux4
Documentation
HomeGetting StartedInstallationIDEsVariablesExecutorsFunctionsConfigurationCommandsHooksSecurityRenderTestingPackage ManagerPackagingGitHub ActionsDocker

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

1... 2 { 3 "name": "has-name", 4 "execute": [ 5 "if(name) && echo 'name exists' || echo 'name does not exist'" 6 ], 7 ... 8 } 9...
1> aux4 has-name
1name does not exist
1> aux4 has-name --name=John
1name exists

Check if variable is empty

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

1... 2 { 3 "name": "is-empty", 4 "execute": [ 5 "if(name==) && echo 'name is empty' || echo 'name is not empty'" 6 ], 7 ... 8 } 9...

Check if variable has specific value

1... 2 { 3 "name": "is-john", 4 "execute": [ 5 "if(name==John) && echo 'name is John' || echo 'name is not John'" 6 ], 7 ... 8 } 9...

Check if variable equals another variable

1... 2 { 3 "name": "is-default", 4 "execute": [ 5 "set:defaultName=John", 6 "if(name==$defaultName) && echo 'name is default' || echo 'name is not default'" 7 ], 8 ... 9 } 10...

Check if variable is not equal

Use != to check inequality.

1... 2 { 3 "name": "is-not-default", 4 "execute": [ 5 "set:defaultName=John", 6 "if(name!=$defaultName) && echo 'name is not default' || echo 'name is default'" 7 ], 8 ... 9 } 10...

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.

1... 2 { 3 "name": "print", 4 "execute": [ 5 "log:cmd param(name) param(age)" 6 ], 7 "help": { 8 "variables": [ 9 { 10 "name": "name", 11 "text": "the name" 12 }, 13 { 14 "name": "age", 15 "text": "the age" 16 } 17 ] 18 } 19 } 20...
1> aux4 print --name Joe --age 20
1cmd --name 'Joe' --age '20'

param with alias

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

1... 2 { 3 "execute": [ 4 "log:cmd param(name:n) param(age:a)" 5 ], 6 ... 7 } 8...
1> aux4 print --name Joe --age 20
1cmd --n 'Joe' --a '20'

param with multiple values

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

1... 2 { 3 "execute": [ 4 "log:cmd param(tag**)" 5 ], 6 "help": { 7 "variables": [ 8 { 9 "name": "tag", 10 "text": "tags", 11 "multiple": true 12 } 13 ] 14 } 15 } 16...
1> aux4 print --tag first --tag second
1cmd --tag 'first' --tag 'second'

params

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

1... 2 { 3 "execute": [ 4 "log:cmd params(name, age, city)" 5 ], 6 ... 7 } 8...
1> aux4 print --name Joe --age 20
1cmd --name 'Joe' --age '20'

Only defined variables are included in the output.

value

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

1... 2 { 3 "execute": [ 4 "log:cmd value(name)" 5 ], 6 ... 7 } 8...
1> aux4 print --name Joe
1cmd 'Joe'

value with multiple values

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

1... 2 { 3 "execute": [ 4 "echo value(text*)" 5 ], 6 "help": { 7 "variables": [ 8 { 9 "name": "text", 10 "text": "text values", 11 "arg": true, 12 "multiple": true 13 } 14 ] 15 } 16 } 17...
1> aux4 process abc def
1["abc","def"]

values

The values function outputs multiple values separated by spaces:

1... 2 { 3 "execute": [ 4 "log:cmd values(name, age, city)" 5 ], 6 ... 7 } 8...
1> aux4 print --name Joe --age 20
1cmd 'Joe' '20' ''

Unlike params, this outputs empty strings for undefined variables.

object

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

1... 2 { 3 "execute": [ 4 "log:cmd object(name, age)" 5 ], 6 "help": { 7 "variables": [ 8 { 9 "name": "name", 10 "text": "the name" 11 }, 12 { 13 "name": "age", 14 "text": "the age" 15 } 16 ] 17 } 18 } 19...
1> aux4 print --name Joe --age 20
1cmd {"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 — 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():

1... 2 { 3 "execute": [ 4 "json:cat data.json", 5 "log:cmd object(response.name:name, response.age:age, response.address.city:city)" 6 ], 7 ... 8 } 9...
1> aux4 print
1cmd {"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:

1... 2 { 3 "execute": [ 4 "log:cmd object($fields)" 5 ], 6 "help": { 7 "variables": [ 8 { 9 "name": "name", 10 "text": "the name" 11 }, 12 { 13 "name": "age", 14 "text": "the age" 15 }, 16 { 17 "name": "city", 18 "text": "the city" 19 }, 20 { 21 "name": "fields", 22 "text": "comma-separated list of fields" 23 } 24 ] 25 } 26 } 27...
1> aux4 print --name John --age 23 --city NYC --fields 'name,age'
1cmd {"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, *).

1... 2 { 3 "execute": [ 4 "log:object(*)" 5 ], 6 "help": { 7 "variables": [ 8 { "name": "name", "text": "the name" }, 9 { "name": "age", "text": "the age" } 10 ] 11 } 12 } 13...
1> aux4 print --name John --age 23
1{"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:

1... 2 { 3 "execute": [ 4 "log:object(name, *:others)" 5 ], 6 ... 7 } 8...
1> aux4 print --name John --age 23
1{"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.

1... 2 { 3 "name": "show-avatar", 4 "execute": [ 5 "log:avatar=nvl(response.avatar[0].path, defaultAvatar, '/images/default.png')" 6 ], 7 ... 8 } 9...

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)
1... 2 { 3 "name": "greet", 4 "execute": [ 5 "log:Hello, nvl(nickname, name, 'stranger')!" 6 ], 7 "help": { 8 "text": "greet someone", 9 "variables": [ 10 { 11 "name": "name", 12 "text": "the name", 13 "default": "" 14 }, 15 { 16 "name": "nickname", 17 "text": "optional nickname", 18 "default": "" 19 } 20 ] 21 } 22 } 23...
1> aux4 greet --nickname Joe
1Hello, Joe!
1> aux4 greet --name John
1Hello, John!
1> aux4 greet
1Hello, 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.

1... 2 { 3 "name": "sync", 4 "execute": [ 5 "log:db=path(db) jobs=path(jobsPath)" 6 ], 7 "help": { 8 "text": "resolve paths", 9 "variables": [ 10 { "name": "db", "text": "database file", "default": "local.db" }, 11 { "name": "jobsPath", "text": "jobs directory", "default": ".jobs" } 12 ] 13 } 14 } 15...
1> aux4 sync
1db=/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:

1... 2 { 3 "name": "backup-dir", 4 "execute": [ 5 "log:path(dir/'backups'/name)" 6 ], 7 "help": { 8 "text": "build a backup path", 9 "variables": [ 10 { "name": "dir", "text": "base directory", "default": "data" }, 11 { "name": "name", "text": "backup name", "default": "shop" } 12 ] 13 } 14 } 15...
1> aux4 backup-dir
1/home/me/project/data/backups/shop

arg

The arg function accesses positional arguments by index, without needing to define a variable with arg: true. 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.

1... 2 { 3 "name": "greet", 4 "execute": [ 5 "echo arg(0) arg(1)" 6 ], 7 "help": { 8 "text": "greet someone" 9 } 10 } 11...
1> aux4 greet hello
1greet hello

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

1... 2 { 3 "execute": [ 4 "echo arg(1) arg(0)" 5 ], 6 ... 7 } 8...
1> aux4 greet hello
1hello 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

1... 2 { 3 "name": "greet", 4 "execute": [ 5 "echo args(*)" 6 ], 7 "help": { 8 "text": "greet someone" 9 } 10 } 11...
1> aux4 greet hello world
1["greet","hello","world"]

args with specific indices

1... 2 { 3 "execute": [ 4 "echo args(0,1)" 5 ], 6 ... 7 } 8...
1> aux4 greet hello
1["greet","hello"]

args with single index

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

1... 2 { 3 "execute": [ 4 "echo args(1)" 5 ], 6 ... 7 } 8...
1> aux4 greet hello
1["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.

1... 2 { 3 "name": "use-file", 4 "execute": [ 5 "set:avatar=nvl(response.avatar[0].path, 'default.png')", 6 "exists(avatar) && cp ${avatar} output/ || echo file not found" 7 ], 8 ... 9 } 10...
1> aux4 use-file

If default.png exists:

1(file is copied)

If it doesn't:

1file 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.

FunctionDefault outputDescription
date()2026-07-21ISO date (local)
time()15:04:05ISO time (local)
datetime()2026-07-21T15:04:05ISO date-time (local, no offset)
utc()2026-07-21T22:04:05ZISO date-time in UTC (Zulu)
epoch()1784665271Unix 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.

1... 2 { 3 "name": "stamp", 4 "execute": [ 5 "log:built on date() at time()" 6 ], 7 ... 8 } 9...
1> aux4 stamp
1built on 2026-07-21 at 15:04:05

Custom formats

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

TokenMeaningTokenMeaning
YYYY / YY4- / 2-digit yearHH / Hhour 24h, padded / not
MMMM / MMMmonth name / abbreviationhh / hhour 12h, padded / not
MM / Mmonth number, padded / notmm / mminute, padded / not
DD / Dday, padded / notss / ssecond, padded / not
dddd / dddweekday name / abbreviationA / aAM-PM / am-pm
Z / ZZUTC 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.

1... 2 { 3 "name": "release", 4 "execute": [ 5 "log:date(MMM, DD, YY) at time(H:mm)" 6 ], 7 ... 8 } 9...
1> aux4 release
1Jul, 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.

1... 2 { 3 "name": "id", 4 "execute": [ 5 "log:req-epoch(ms)" 6 ], 7 ... 8 } 9...
1> aux4 id
1req-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.

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).

CallResult
uuid()019f8661-8b26-7a0c-9d10-501669d7aa67 (v7)
uuid(7)version 7 (explicit)
uuid(4)27f0ae22-0961-4f34-8179-64bcf4e39dbc (v4)
1... 2 { 3 "name": "new-record", 4 "execute": [ 5 "set:id=uuid()", 6 "log:created record ${id}" 7 ], 8 ... 9 } 10...
1> aux4 new-record
1created 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.

1... 2 { 3 "name": "recent", 4 "execute": [ 5 "db query \"SELECT \\uuid(), \\date(created_at) FROM events\"" 6 ], 7 ... 8 } 9...
1SELECT 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:

1... 2 { 3 "execute": [ 4 "json:cat data.json", 5 "log:cmd params(response.name, response.age, response.address.city)" 6 ], 7 ... 8 } 9...

Given data.json:

1{ 2 "name": "Joe", 3 "age": 20, 4 "address": { 5 "city": "New York", 6 "state": "NY" 7 } 8}
1> aux4 print
1cmd --responseName 'Joe' --responseAge '20' --responseAddressCity 'New York'

For values with nested data:

1... 2 { 3 "execute": [ 4 "json:cat data.json", 5 "log:cmd values(response.name, response.age, response.address.city)" 6 ], 7 ... 8 } 9...
1cmd 'Joe' '20' 'New York'

See Also