Built-in commands

These commands are part of luish. In an interactive shell, help lists them and help NAME shows the same text as here in the terminal.

.

. file
source file [argument ...]

Run the commands in a file in the current shell.

The commands can change the shell’s variables, functions, options and working directory, as if they had been typed. If file has no /, it is searched for in PATH (the current directory is not searched unless it is in PATH). A return in the file stops reading it.

The exit status is that of the last command run, or 0 if there was none. A file that can’t be read is an error, which exits a shell that isn’t interactive.

source is not in POSIX; it works as in zsh. It is the same as ., except that a file without / is looked for in the current directory first, and then in PATH. Any arguments become the positional parameters ($1, …) while the file runs, and the previous ones are restored afterwards.

:

: [argument...]

Do nothing, successfully.

The arguments are expanded, so : is useful for expansions that have side effects, such as : ${VAR:=default}. The exit status is 0. : is a special built-in: assignments before it stay set.

__luish_internal

__luish_internal bindkey [arg...]
__luish_internal check-cache [-q] [rc|login|startup]...
__luish_internal clipcopy [file]
__luish_internal complete line
__luish_internal default-config [--extra]
__luish_internal function-file name file [lines [dir]]
__luish_internal help [name...]
__luish_internal list-completions
__luish_internal plugin subcommand [arg...]
__luish_internal print [arg...]
__luish_internal print-git-rev
__luish_internal print-git-rev-short
__luish_internal savestate
__luish_internal style [arg...]
__luish_internal where [-a] [name...]

Run one of luish’s own commands.

luish’s own commands are subcommands of this built-in, so that they don’t take names that scripts might use for something else.

bindkey

Show or change the line editor’s key bindings (see help bindkey).

check-cache

Check the startup caches (all of this host’s, or those named): run the startup files again, in a new shell started as the one that built the cache, and compare the result with what the cache restores. Show when each cache was generated and last checked (in local time), and what differs. A cache that is up to date is touched; one that differs is rebuilt. With -q (--quiet), show only the caches that were rebuilt. The status is 0 if all were up to date, 1 if any was rebuilt, 2 on errors.

clipcopy

Put text on the clipboard through the terminal (see help clipcopy).

complete

Print what Tab offers for the last word of line, as the line editor would complete it (with the completers of loaded plugins), one match per line: the text that replaces the word, with the space or / that ends a single match, then a tab and the match’s description, if it has one. The status is 1 if there are no matches, or if a completer failed. It works in any shell, for example to test a completer from a script.

default-config

Print the recommended config.toml, as luish offers to write it the first time it runs and as the install script writes it, with the luish-extra plugins (completion for more commands, and colour schemes). --extra, which used to add them, is accepted and does nothing.

function-file

Record that the function name was defined in file, which is then BASH_SOURCE while it runs and named in its error messages. The state that savestate prints uses it, since reading it back defines the functions again: lines are the line numbers of the body in file (each as the difference from the one before, separated by commas), which its text written again doesn’t have, and dir the directory that a relative file is in. Without lines (or if they don’t fit the body), errors name no line. The status is 1 if there is no such function, 2 if lines has characters other than digits, , and -.

help

Show help for built-in commands (see help help).

list-completions

Print the commands that the extensions of loaded plugins provide completers for, sorted, one per line: the command (-default- for the completer of commands that have none of their own), then a tab and the name of the plugin.

plugin

Load, list, unload and fetch plugins (see help plugin).

print

Write the arguments, as zsh’s print (see help print).

print-git-rev, print-git-rev-short

Print the git revision luish was built from (the full or abbreviated hash), with -dirty if its sources differed from it, or unknown if it wasn’t built from a git checkout.

savestate

Print commands that recreate the state of the shell when read back with .: the working directory, the file mode mask, variables (with their export and readonly attributes), traps, functions, aliases, loaded plugins, key bindings changed with bindkey, styles and colour schemes, and options. Restoring adds to the current state: nothing is unset.

style

Show or change styles and colour schemes (see help style).

where

Show where variables were set, while variable tracing is on (see help where).

A missing or unknown subcommand is an error with exit status 2.

alias

alias [{+|-}gmrsL] [name[=value]...]

Define or show aliases.

alias name=value makes the word name, when it is the first word of a command, stand for value. If value ends in a blank, the next word is checked for an alias too. Without arguments, alias lists the regular and global aliases, in a form that can be read back; alias name shows one. The exit status is 1 if one of the names isn’t an alias.

An alias takes effect from the next line that is read, not on the line that defines it.

The options are based on zsh’s alias command:

  • -g defines a global alias, which is expanded wherever it is a word of its own, not only as a command name: after alias -g G='| grep', ls G foo runs ls | grep foo. It isn’t expanded when quoted ('G' or \G), as a here-document delimiter, or as a reserved word.

  • -s defines a suffix alias: a command name that ends in . and the suffix, with something before the ., is run with the alias’s value in front. After alias -s pdf=evince, the command notes.pdf runs evince notes.pdf.

  • -r, -g and -s select regular, global or suffix aliases for listing (only -s lists suffix aliases, which have a table of their own).

  • -m takes the names as patterns (quote them), and lists the aliases that match.

  • -L lists aliases as alias commands, with -g or -s as needed.

  • + instead of - (or a + on its own after the options) lists the names only.

Since an argument that starts with - or + is an option, put -- before a name that starts with one: alias -- -x='...'.

Aliases can also be defined in config.toml (see “Settings in config.toml” in the user guide).

bg

bg [job...]

Continue a stopped job in the background.

The job (by default the current one) is continued as if it had been started with &. This needs job control (the monitor option, on in interactive shells). See help jobs for how to name a job.

bindkey

bindkey [-L] [key [widget]]
bindkey -r key...
bindkey -e | -v

Show or change the line editor’s key bindings, as in zsh.

With no arguments, bindkey lists the bindings, one per line as "KEY" widget; with -L, as bindkey commands. With a key, it shows what the key is bound to, and with a key and a widget, it binds the key to the widget. bindkey -r removes luish’s binding of each key, which then does what the line editor does by default. -e selects emacs mode and -v vi mode (as set -o emacs and set -o vi do). -M emacs or -M main may be given; there are no other keymaps.

Keys can be written by name: Up, Down, Left, Right, Home, End, Insert (or Ins), Delete (Del), PageUp (PgUp), PageDown (PgDn), F1 to F12, Tab, Enter (Return), Backspace, Esc and Space, or as the character they type, after any of the modifiers Ctrl-, Alt- and Shift- (also C-, M- or Meta-, and S-, and with + for -). Names and modifiers can be in any case, but characters can’t: Alt-b and Alt-B are different keys (Alt-B is Alt-Shift-b). A sequence of keys is written with spaces between them:

bindkey Up up-line-or-history
bindkey Ctrl-Right forward-word
bindkey 'Ctrl-X Ctrl-E' undo

Keys can also be written as in zsh: ^X is Ctrl-X (and ^? is Backspace), ^[ or \e is Esc, which comes before a key typed with Alt (^[. is Alt-.), and \C-x and \M-x are Ctrl-X and Alt-X. Other keys are written as the escape sequences that xterm sends: ^[[A is Up (^[OA is the same key), ^[[1;5C is Ctrl-Right, ^[[3~ is Delete. A key may be a sequence of keys, as ^X^E. An argument is read this way unless it is made of names (or characters with modifiers), so ^X Up is Ctrl-X, space, U and p; to bind the characters of a name, write the first one with a backslash (\Up) or in octal, as bindkey shows them (\125p). Listings always show the escape sequences.

The bindings apply in emacs mode. In vi mode the keys are the line editor’s own. The widgets are zsh’s, by the same names:

accept-line, accept-line-and-down-history (run the line, and start the next one with the history entry after it), backward-char, backward-delete-char, backward-kill-line, backward-kill-word, backward-word, beginning-of-buffer-or-history, beginning-of-history, beginning-of-line, capitalize-word, clear-screen, delete-char, down-case-word, down-history, down-line-or-history, end-of-buffer-or-history, end-of-history, end-of-line, expand-or-complete (Tab: expand the word before the cursor, or else complete it), forward-char, forward-word, history-beginning-search-backward and -forward (the previous or next history entry that starts with the text before the cursor), history-incremental-search-backward and -forward, insert-last-word (the last word of the previous command; again, that of the one before), kill-buffer, kill-line, kill-whole-line, kill-word, quoted-insert, redisplay, send-break, transpose-chars, transpose-words, undefined-key (do nothing), undo, up-case-word, up-history, up-line-or-history, yank and yank-pop.

The word widgets take as words the letters and digits and the characters in $WORDCHARS (default: *?_-.[]~=/&;!#$%^(){}<>).

The default bindings are zsh’s for emacs mode, except that Up and Down (^[[A and ^[[B) are bound to history-beginning-search-backward and -forward: with an empty line they go through the history as usual.

The exit status is 1 if a key sequence or a widget is not valid, or a key can’t be typed (such as Ctrl-Tab, which terminals send as Tab).

Key bindings can also be set in config.toml, in its bindkey table.

break

break [n]

Exit from the innermost for, while or until loop.

With n, exit from n nested loops (all of them, if there are fewer). Outside a loop, break does nothing.

builtin

builtin [name [argument...]]

Run a built-in, bypassing functions.

builtin name args runs the built-in name, even if a function of the same name exists, as in zsh and bash. It is not in POSIX. If there is no such built-in, it prints an error and its status is 1: unlike command, it never runs a program. A special built-in run this way stays special, so its errors (such as builtin set -o bogus) exit a non-interactive shell. It also runs the commands that plugins add in Rhai (sh::builtin).

caller

caller [n]

Show where the current function was called from.

As bash’s caller, for a function or a file read with ..

Without n, print the line of the call and the file it is in (NULL at the top level of a script). With n, print the line, the name of the caller and its file for the nth frame of the call stack, counting from 0 for the innermost: the elements n of BASH_LINENO and n+1 of FUNCNAME and BASH_SOURCE. The caller of a function is main at the top level of a script, and source in a file read with ..

The status is 1 if there is no such frame: outside a script, a function and a file read with ., or for an n past the end of the stack.

die() {
    echo "error: $1" >&2
    caller 0 >&2    # 12 main script.sh
    exit 1
}

cd

cd [-L | -P [-e]] [directory]
cd -
chdir ...

Change the working directory.

Without a directory, cd goes to $HOME; cd - goes back to the previous directory ($OLDPWD) and prints its name. A relative directory that doesn’t start with . or .. is looked for in each directory of CDPATH; if it is found through CDPATH, the new directory is printed. PWD and OLDPWD are set and exported. chdir is another name for cd.

With setopt pushd.auto, cd also pushes the previous directory onto the directory stack, and cd +n or cd -n takes that entry out of the stack and goes to it (see pushd).

-L

Follow the path as given: .. removes the last component of the logical path (with symbolic links not resolved). This is the default.

-P

Use the physical directory, with symbolic links resolved.

-e

With -P, return 1 if the directory was changed but its name can’t be found (for example, because it was removed). PWD is then set to the logical path. Without -e, cd returns 0 in that case.

The exit status is 0 on success, 1 in the case of -e above, and 2 if the directory can’t be changed.

clipcopy

clipcopy [file]

Put text on the clipboard, through the terminal.

clipcopy reads file (or standard input, if there is no file or it is -) and asks the terminal to put it on the system clipboard, with the escape sequence for that (OSC 52), written to /dev/tty. It works over ssh, since the terminal on your side does it, and needs no xclip, wl-copy or pbcopy:

git log -1 --format=%H | clipcopy
clipcopy ~/.ssh/id_ed25519.pub

The text is copied as it is, with its final newline if it has one.

Most terminals take it: kitty, WezTerm, Ghostty, foot, Alacritty, iTerm2 (once allowed in its settings), Windows Terminal and xterm (with allowWindowOps), but not GNOME Terminal and other VTE ones. Some limit how much text they take. In tmux it needs set -g set-clipboard on.

clipcopy is a built-in only in interactive shells (and their subshells), so that scripts find the same commands as they do in dash. __luish_internal clipcopy is the same command in any shell. A function named clipcopy (such as oh-my-zsh’s) is used instead of the built-in.

The status is 0 if the text was sent to the terminal, which doesn’t say whether the terminal took it; 1 if the file can’t be read or there is no terminal; 2 for a usage error.

command

command [-p] command [argument...]
command [-p] -v | -V name

Run a command, bypassing functions, or describe it.

command name args runs name as a built-in or a program, even if a function of the same name exists. Errors in special built-ins run this way (such as a failed assignment in command export) don’t exit the shell.

-p

Search a default PATH that finds the standard utilities, instead of $PATH.

-v

Print how name would be run: the path of a program, or just the name of a built-in, function or keyword, and an alias as the alias command that defines it. The exit status is 127 if it isn’t found.

-V

Describe name in words, as type does.

continue

continue [n]

Go on to the next iteration of the innermost loop.

With n, continue the nth enclosing loop (the outermost, if there are fewer). Outside a loop, continue does nothing.

pushd, popd, dirs

pushd [-qLP] [directory | +n | -n]
popd [-qLP] [+n | -n]
dirs [-lpv]
dirs -c
dirs directory ...

Keep a stack of directories to go back to.

These commands are not in POSIX; they work as in zsh. The stack is listed with the current directory first, as entry 0, then the directories that were pushed, most recent first. +n names entry n from the start of this list, and -n entry n from its end (-0 is the last one).

pushd directory changes to the directory as cd does (pushd - goes to $OLDPWD) and pushes the previous one onto the stack. Without a directory, it swaps the top two entries (it goes to $HOME if the stack is empty). pushd +n or -n goes to that entry and rotates the stack, so that the entries before it move to the end.

popd removes the top of the stack and goes to it; the entry is removed even if the directory can’t be changed to. popd +n or -n removes that entry instead, without changing directory.

The array dirstack holds the stack without the current directory, so that ${dirstack[0]} is entry 1; assigning an array to it, as in dirstack=(~/src /tmp), replaces the stack.

In an interactive shell, pushd and popd print the stack afterwards, as dirs does, unless pushd.silent is set.

Three of zsh’s options (see setopt) change how the stack is kept: pushd.auto (zsh’s auto_pushd) makes cd push the previous directory, as pushd does, and lets it take +n and -n to take that entry out of the stack and go to it. pushd.ignore_dups keeps one copy of each directory: after cd, pushd or popd, the new directory is removed from the stack. pushd.silent stops pushd and popd from printing the stack.

-q

For pushd and popd: don’t print the stack.

-L, -P

For pushd and popd: as for cd, except that -P wins over -L whatever their order.

dirs prints the stack on one line, with $HOME shown as ~.

-l

Print full names, without ~.

-p

Print one directory per line.

-v

Print one directory per line, with its number.

-c

Clear the stack.

dirs directory ... replaces the stack (after the current directory) with the directories given.

The exit status is 0 on success, and 1 if the directory can’t be changed or the entry doesn’t exist.

disown

disown [-ahr] [job...]

Remove jobs from the job table.

A job that is disowned keeps running, but the shell forgets it: jobs doesn’t list it, its end isn’t reported, wait without arguments doesn’t wait for it, and exit doesn’t warn about it if it is stopped. Without arguments, disown removes the current job, so command & disown starts a command that the shell then leaves alone; zsh’s command &| and command &! do the same. See help jobs for how to name a job; as in bash, a job can also be named by the process id of one of its processes, such as $!.

A stopped job stays stopped once disowned, with a warning that says how to continue it (kill -CONT).

This command is not in POSIX; it works as in zsh, with bash’s options:

-a

Remove all jobs.

-r

Remove only running jobs: all of them, if no job is named.

-h

Leave the jobs in the table. In bash, this keeps the shell from sending them SIGHUP when it exits; luish never does that, so -h does nothing.

The exit status is 1 if there is no current job, or a job named doesn’t exist (the others are still removed), and 0 otherwise.

echo

echo [-n] [argument...]

Print the arguments, separated by spaces.

A newline follows, unless the first argument is -n (no other options are recognised). Backslash escapes in the arguments are always interpreted:

\a \b \f \n \r \t \v

Alert, backspace, form feed, newline, carriage return, tab, vertical tab.

\e

Escape.

\\

A backslash.

\0nnn, \nnn

The byte with the octal value nnn (up to three digits).

\c

Print nothing more, not even the newline.

For portable output, printf is a better choice.

eval

eval [argument...]

Run the arguments as a command.

The arguments are joined with spaces, and the result is parsed and run in the current shell. The exit status is that of the command, or 0 if there is none.

var=HOME
eval "echo \$$var"      # prints the value of $HOME

exec

exec [command [argument...]]

Replace the shell with a command, or redirect the shell.

With a command, the shell process becomes that command, which is searched for in PATH (functions and built-ins are not used). A command that can’t be run exits the shell with status 126 or 127.

Without a command, the redirections on exec apply to the shell itself from then on:

exec 3>log.txt      # open fd 3 for the rest of the script
exec >&3 2>&1       # send all output there

exit

exit [n]

Exit the shell.

The exit status is n, or that of the last command run if n is not given. A trap on EXIT runs first. In an interactive shell with stopped jobs, exit only warns about them the first time; exiting again right away works.

export

export name[=value]... name=(value...)...
export -p

Pass variables to the commands the shell runs.

Each variable is marked for export, and set to value if one is given. Arguments that look like assignments are expanded as assignments are (no field splitting or globbing), so export PATH=$PATH:~/bin needs no quotes. Without names, or with -p, export lists the exported variables as commands that can be read back.

export name=(a b c) assigns an array, but arrays aren’t passed to commands, as in zsh and bash.

false

false

Do nothing, unsuccessfully (exit status 1).

false ignores its arguments.

fc

fc [-e editor] [-nlr] [first [last]]
fc -s [old=new] [first]

List, or edit and run again, commands from the history.

first and last select a range of the history: a positive number is an event number, a negative one counts back from the latest command, and anything else selects the latest command that starts with it. fc itself isn’t in the history it works on.

By default, the commands are written to a file and an editor is opened on it ($FCEDIT, else $EDITOR, else ed); when the editor exits, the file is run, and replaces the fc command in the history.

-e editor

Use editor. -e - runs the commands without editing them, as -s.

-l

List the commands (by default the last 16) instead.

-n

With -l, leave out the event numbers.

-r

Reverse the order of the commands.

-s

Run the command again (by default the latest) without editing it; with old=new, the first old in it is replaced by new first.

fc only works in interactive shells.

fg

fg [job...]

Continue a job in the foreground.

The job (by default the current one) gets the terminal, is continued if it was stopped, and the shell waits for it. The exit status is that of the job. This needs job control (the monitor option, on in interactive shells). See help jobs for how to name a job.

getopts

getopts optstring name [argument...]

Parse options, one per call.

Each call stores the next option letter in the variable name, and its argument, if it has one, in OPTARG. OPTIND is the index of the next argument to look at, and starts at 1. The options are taken from the arguments, or from the positional parameters if there are none. At the end of the options, name is set to ? and the exit status is 1.

optstring lists the option letters; a letter followed by : takes an argument. An unknown option or a missing argument sets name to ? and prints a message. If optstring starts with :, nothing is printed: name is set to ? for an unknown option and to : for a missing argument, and OPTARG is set to the option letter.

while getopts vo: opt; do
    case $opt in
        v) verbose=1 ;;
        o) output=$OPTARG ;;
        *) exit 2 ;;
    esac
done
shift $((OPTIND - 1))

hash

hash [-r] [name...]

Remember or forget where commands are found.

The shell remembers where it found each command in PATH. Without arguments, hash prints the remembered paths. With names, it looks each one up in PATH and remembers it (the exit status is 1 if one isn’t found).

-r

Forget all remembered paths.

Assigning PATH also forgets them. An interactive luish forgets them by itself when a directory in PATH changes, so hash -r isn’t needed after installing a command.

help

help [name...]

Show help for built-in commands.

Without arguments, help lists the built-ins, each with a one-line summary. With names, it shows the help for each of them. The exit status is 1 if there is no help for one of the names. On a terminal, the help is shown in the colours of the colour scheme in use (see style), unless $NO_COLOR is set.

help is a built-in only in interactive shells (and their subshells), so that scripts find the same commands as in other shells, where help may be something else. Anywhere, __luish_internal help does the same.

jobs

jobs [-l | -p] [job...]
jobs -i [job]

List background and stopped jobs.

Each job is shown with its number, its state and its command. The current job (the default for fg and bg) is marked + and the previous one -. Finished jobs are listed once and then forgotten.

-l

Also show the process ID of each process in the job.

-p

Show only the process group ID of each job.

-i

Show a menu of the jobs, on the terminal, to act on them (see below), with job selected (by default the current job).

The menu lists every job with its number, process ID, state and command, and follows them as they change. Up and Down (or j and k), or a job’s number, choose a job, and these keys act on it:

f or Enter

Bring it to the foreground, as fg does (this leaves the menu).

b

Continue it in the background, as bg does.

s

Stop it (with STOP).

K

List the signals that end it. The next key sends one: t for TERM, e for TERM and then KILL if the job hasn’t ended 5 seconds later, k for KILL, i for INT and h for HUP. Any other key sends nothing, so a job is never ended by one key. A stopped job is continued after the signal, so that it can act on it.

q, Esc or Ctrl-C leave the menu. If KILL is still to be sent, leaving waits for it (Ctrl-C again leaves without sending it). Jobs that stopped or ended are reported before the next prompt, as usual.

A job is named by %n (its number), %+ or %% (the current job), %- (the previous job), %string (the job whose command starts with string) or %?string (the job whose command contains string).

kill

kill [-s signal | -signal] pid | job...
kill -l [status]

Send a signal to processes or jobs.

The signal (by default TERM) is given as a name, with or without SIG, in any case (-s hup, -HUP), or as a number (-9). A negative pid signals a process group. A job (see help jobs) is signalled as a whole.

-l

List the signal names. With an exit status, show the name of the signal that caused it (kill -l 130 shows INT).

let

let expression...

Evaluate arithmetic expressions.

let evaluates each argument as an arithmetic expression, as in $((...)), so let x=1+2 'y = x * 3' sets x and y. It is not in POSIX, and follows zsh. Its status is 0 if the value of the last expression is non-zero and 1 if it is zero, so let 'n > 0' works as a test. An invalid expression prints an error, stops at that argument and gives status 1, without exiting the shell. Arguments are expanded like those of any command, so quote those with *, spaces or other characters special to the shell. Unlike zsh, arithmetic is on integers only.

local

local [-aAilruUx] [+ilruUx] name[=value]... name=(value...)...
local -

Make variables local to a function.

Each variable gets a new value (value, or, without one, the value it has) that lasts until the function returns, when the previous value and attributes are restored. Functions called from this one see the local variable. Using local outside a function is an error.

local - makes the options that set sets (as shown by $- and set -o) local: they are restored when the function returns, as in dash. luish’s own options, set with setopt, are not restored.

local name=(a b c) makes a local array. The options (not POSIX) set attributes, as for typeset, which also makes local variables, but starts them unset.

plugin

plugin load name|source/path|path [option=value...]...
plugin load -c code name
plugin list-loaded
plugin list-available [-a]
plugin unload name...
plugin run file|-c code [arg...]
plugin add [-y] plugin [name]
plugin sync [-q]
plugin update [-q] [source...]
plugin check [-q]

Load, unload and fetch plugins.

plugin load loads each plugin: name is the source called name in config.toml’s plugins.available (or std, or a source that an enabled plugin’s plugin.toml makes available), else the first of the Rhai file name.rhai, the shell file name.lsh and the directory name in $XDG_CONFIG_HOME/luish/plugins (by default ~/.config/luish/plugins); source/path is the plugin at path in the collection source (name, or sub/name in its sub-collection sub); and any other argument that contains a / is a path. A plugin of a collection is loaded under the name source/path, others under their file’s or directory’s name. A directory plugin runs its init.lsh, then its extension.rhai, then (in interactive shells) its rc.lsh and post-rc.lsh; during the startup files of rc.d, post-rc.lsh waits for their end. The dependencies that a plugin’s plugin.toml lists are loaded first, unless they are already loaded. A plugin whose plugin.toml has luish-version = "X.Y" isn’t loaded by an older luish, nor are the plugins that depend on it. The option=value arguments after a plugin are its options, which its plugin.toml declares (see the plugins page of the documentation); a plugin that is already loaded, as a dependency or otherwise, must be given the same options, or unloaded first. Loading a plugin again reloads it. The exit status is 1 if a plugin can’t be loaded. At the prompt of an interactive shell with a terminal for output, plugin load and plugin unload say what they did (Loaded NAME, Reloaded NAME, Unloaded NAME, marking dependencies); they are silent in startup files, functions and command substitutions.

plugin load -c loads the Rhai code code as the plugin name (which can’t contain a /), with the current directory as its directory. It replaces a plugin of that name loaded with -c, but not one loaded from a file or directory, which must be unloaded first (the exit status is then 1); loading a plugin of that name from a file replaces it, with a warning.

plugin list-loaded prints the names of the loaded plugins (on a terminal, No plugins loaded if there are none), and plugin list-available the names of the plugins that plugin load can load by name and that aren’t loaded: those in the plugin directory, and those of the sources in config.toml that are installed, except the libraries (plugins for other plugins to use, whose plugin.toml says library = true), which -a (or --all) adds. plugin unload removes plugins and their hooks; each is named as plugin list-loaded shows it, or as plugin load was given it (such as std/NAME).

plugin run runs the Rhai file file, or the Rhai code code, once, without loading a plugin: it can’t register hooks, completers or commands (that is an error: use plugin load -c), and it doesn’t unload or reload any plugin. The Rhai variable argv is an array of file (or -c) and the args. The exit status is the value of the last statement (or of return), if it is an integer (modulo 256) or a boolean (true is 0, false 1), and otherwise 0; it is 1 if the code can’t be read or fails. import is relative to file, or with -c, to the current directory, and the modules are read again for each run. --no-plugins doesn’t stop it.

plugin add adds a plugin to config.toml and installs it. plugin is a GitHub repository (owner/repo, gh:owner/repo, or a URL such as https://github.com/owner/repo, where /tree/branch/dir gives a branch and a directory), another git URL (https://..., git@host:path), a local path (one that exists, or starts with /, ./, ../ or ~, or a file:///path URL, which is a git source if path is a git repository), or a plugin of a source that config.toml names (source/path, such as std/name) or of the plugin directory (name). A git source is fetched first, into a temporary directory, to see what it holds: a source that is neither a plugin nor has any (a .rhai or .lsh file, or a directory with one of a plugin’s files) is not added. It is added to plugins.enabled, as name = { gh = "owner/repo" } for a source (a collection of more than one plugin goes to plugins.available, to load its plugins with plugin load source/path), keeping the file’s comments. The name is the repository’s, file’s or directory’s, unless name is given. It prints the line it adds and asks before changing the file (reading the answer from standard input), unless -y (or --yes) is given; then it says what it added, runs plugin sync and loads the plugin. The exit status is 1 if it was declined, if the name is already used, or if the source can’t be fetched (then config.toml isn’t changed).

plugin sync fetches, with git, the sources of the plugins in config.toml’s plugins.enabled (and of their dependencies), of its plugins.available and of the sources that the enabled plugins make available (in their plugin.toml’s [available]), and records the commit of each in plugins.lock, next to config.toml, with the sources that the plugins make available. A source that is already in plugins.lock stays at its commit. plugin update fetches the newest commit of each git source, or of the sources named, and updates plugins.lock. Both print the sources they fetch, those whose commits changed (Updating SOURCE OLD..NEW, with a link to the changes for a GitHub source), with plugin update also those that didn’t, each with the enabled plugins that come from it, and the number of git sources locked and the plugins enabled; with -q (or --quiet) they print only errors. plugin check asks each git source (with git ls-remote) for its newest commit and says, for each, whether it is up to date, pinned to a commit (rev, which has nothing newer) or has a newer commit than the locked one, and which sources aren’t installed, without fetching or changing anything; with -q it prints only the sources that can be updated and those that aren’t installed. Its exit status is 0 unless a source couldn’t be checked. Interactive shells load the plugins in plugins.enabled at startup, from the commits in plugins.lock, without running git. With --no-plugins, plugin load, plugin add, plugin sync, plugin update and plugin check do nothing.

plugin is a built-in only in interactive shells (and their subshells). Anywhere, __luish_internal plugin does the same.

On a terminal (unless $NO_COLOR is set), what these commands print is coloured with the styles plugin.name, plugin.ok, plugin.update, plugin.warn, plugin.error and plugin.dim of the colour scheme in use (style).

See the plugins page of the documentation for how to write plugins and list them in config.toml, and the extensions page for their Rhai code.

print

print [-abcDilmnNoOPrsz] [-C cols] [-f format] [-u fd] [-v name]
      [-x|-X tab-stop] [--] [arg...]
print -R [-en] [arg...]

Write the arguments, as zsh’s print does.

print is a built-in only in interactive shells (and their subshells), so that scripts find the same commands as they do in dash, where print may be a program. __luish_internal print is the same command in any shell.

The arguments are written separated by spaces and followed by a newline. Backslash escapes in them are expanded: \a, \b, \e (or \E), \f, \n, \r, \t, \v and \\; \NNN (one to three octal digits) and \xNN (one or two hex digits) for a byte; \uNNNN and \UNNNNNNNN for a Unicode character, written as UTF-8; \M-c and \C-c for the meta and control versions of a character (\C-? is DEL); and \c, which ends the output there, without the newline. A backslash before any other character is removed.

-r

Don’t expand backslash escapes.

-R

Emulate BSD echo: don’t expand escapes, and take only -e (do expand them) and -n as options in the words that follow, as echo does.

-b

Also recognise the escapes of bindkey: ^c is the control version of c. \c is then just c.

-P

Expand % sequences as in prompts (see setopt prompt.percent), after the backslash escapes: print -P '%F{red}%~%f' writes the current directory in red.

-D

Replace $HOME at the start of an argument with ~.

-m pattern

Keep only the arguments that match the pattern (the first argument).

-o, -O

Sort the arguments in ascending or descending byte order; with -i, ignore case.

-n

Don’t write the newline at the end.

-l

Separate the arguments by newlines instead of spaces.

-N

Separate and end the arguments with NUL bytes (-l still separates them by newlines).

-c

Write the arguments in columns, filled downwards, as many as fit in $COLUMNS (or the terminal’s width, or 80 columns).

-C cols

Write the arguments in cols columns.

-a

With -c or -C, fill the rows across rather than the columns down.

-x tab-stop, -X tab-stop

Expand the tabs at the start of each line (-x) or all tabs (-X) to spaces, with tab stops every tab-stop columns.

-f format

Format the arguments as printf does. The arguments’ escapes aren’t expanded, but -P still applies.

-u fd

Write to file descriptor fd instead of standard output.

-v name

Set the variable name to the output instead of writing it, without the final newline.

-s

Add the arguments, separated by spaces, to the history as a new entry, instead of writing them.

-z

Start the next command line with the arguments, separated by spaces, instead of writing them. Several pushed lines come back in the reverse order.

Options can be grouped (-lP), and the argument of -C, -f, -u, -v, -x and -X can follow the letter or be the next word. - or -- ends the options, and so does an argument that starts with - and a digit, such as a negative number.

zsh’s -p (write to the coprocess) always fails, as luish has no coprocesses, and -S is not supported.

The exit status is 0, unless an option is invalid, -u names a file descriptor that isn’t open, or the variable of -v can’t be set, which is reported with status 1; or a conversion of -f failed, as with printf.

printf

printf format [argument...]

Print the arguments according to a format.

The format is printed with backslash escapes (as in echo) interpreted and each conversion replaced by the next argument. If arguments remain, the format is used again. Missing arguments count as empty strings or zero.

%s %c

A string; its first character.

%d %i %u %o %x %X

An integer, in decimal, octal or hexadecimal. An argument that starts with a quote stands for the value of the character after it.

%f %e %g %E %G %a %A

A floating-point number.

%b

A string, with backslash escapes in it interpreted, as echo does.

%%

A % sign.

Flags (-, +, space, #, 0), a width and a precision may come after the %, as in C; * takes them from the arguments.

printf '%-10s|%5.2f\n' name 3.14159    # name      | 3.14

pwd

pwd [-L | -P]

Print the working directory.

-L

Print the logical directory, as cd reached it (which may contain symbolic links). This is the default.

-P

Print the physical directory, with symbolic links resolved.

read

read [-r] [-p prompt] name...
read [-r] [-p prompt] -A name
read [-r] [-p prompt] -a name

Read a line from standard input into variables.

The line is split into fields with IFS, as in field splitting: each name gets one field, and the last one gets the rest of the line (without leading and trailing IFS whitespace). Names left over are set to empty. The exit status is 1 at the end of the input (the variables are still set from what was read).

Unless -r is given, a backslash quotes the next character, and a backslash at the end of the line continues it on the next line.

-r

Treat backslashes as ordinary characters.

-p prompt

Print prompt on standard error first, if standard input is a terminal.

-A

Read the fields into the array name (not POSIX; as in zsh). The line is split as for several names, but the last field ends at the next delimiter too; an empty line gives an empty array. An associative array gets pairs of keys and values.

-a name

The same as -A (as in bash).

while IFS=: read -r user _ uid _; do
    echo "$user has uid $uid"
done < /etc/passwd

readonly

readonly name[=value]... name=(value...)...
readonly -p

Make variables read-only.

Each variable is set to value, if one is given, and can’t be assigned or unset afterwards (in this shell and its subshells). Without names, or with -p, readonly lists the read-only variables as commands that can be read back. readonly name=(a b c) makes a read-only array, whose elements can’t be assigned either.

return

return [n]

Return from a function or a file read with ..

The exit status is n, or that of the last command run if n is not given.

set

set [-abCefhImnuvx] [-o option]... [argument...]
set [+abCefhImnuvx] [+o option]... [argument...]
set -- [argument...]
set -o | +o

Set options or positional parameters.

Without arguments, set lists all variables. -x turns an option on and +x turns it off, and -o name and +o name do the same by name. set -o shows the options, and set +o shows them as commands that restore them. Arguments after the options replace the positional parameters ($1, $2, …); set -- with no arguments after it removes them all.

-a allexport

Export every variable that is assigned.

-b notify

Report finished background jobs at once. Accepted, but not implemented yet: they are reported before the next prompt.

-C noclobber

> doesn’t overwrite existing files (>| still does).

-e errexit

Exit when a command fails, except in conditions (if, while, the left of && and ||, after !).

-f noglob

Don’t expand filename patterns.

-h hashall

Accepted, as POSIX requires; luish remembers where every command is found anyway.

-I ignoreeof

Don’t exit an interactive shell on end of file (Ctrl-D).

-m monitor

Job control: run each job in its own process group. On in interactive shells.

-n noexec

Read commands without running them (ignored in interactive shells).

-u nounset

Expanding an unset variable is an error.

-v verbose

Print input lines as they are read.

-x xtrace

Print each command, after expansion, before it runs (prefixed by $PS4).

-o pipefail

A pipeline’s status is that of its last command that failed, or 0 if none did (not only that of its last command). A background pipeline keeps the setting it started with.

-E emacs, -V vi

Line editing mode of an interactive shell.

luish’s own options, beyond these, are set with setopt and unsetopt, which also take the names above.

setopt, unsetopt

setopt [-p group] [option[=value]...]
unsetopt [-p group] [option...]

Turn options on or off by name, and set settings.

These commands are not in POSIX; they work as in zsh. They set the options that set does, by their long names (see set), and also luish’s own options, which set -o doesn’t show or accept, so that it behaves as in dash. luish’s own options have names in groups, such as history.share; their earlier names (such as sharehistory) and zsh’s (share_history) also work. Case doesn’t matter and _ is ignored, so PROMPT_PERCENT and promptpercent are the same option. A no prefix inverts a name: setopt no_err_exit is unsetopt errexit, unsetopt glob is setopt noglob, and setopt history.no_share is unsetopt history.share.

setopt option=value sets an option on (true, on, yes or 1) or off (false, off, no or 0), or sets a setting that has a value (see below). As for export, an argument of this form is expanded as an assignment: a ~ after the = (or after a :) is expanded, and the value isn’t split into fields, so setopt history.file=~/.history works.

Without arguments, setopt lists the options that are on and unsetopt the options that are off, in alphabetical order.

-p group

The names that follow are in group: setopt -p history share file=~/.history is setopt history.share history.file=~/.history, and setopt -p history no_share is setopt history.no_share. Without names, setopt -p group and unsetopt -p group print the group’s settings, in alphabetical order, as the commands that set them (setopt history.share, unsetopt history.ignore_space, setopt history.file='...'); a setting with a value is left out if its variable isn’t set. If -p is given more than once, the last one counts. The groups are cd, editor, expand, glob, highlight, history, prompt and pushd.

luish’s own options, all off by default:

prompt.percent (promptpercent)

Expand % sequences in PS1, PS2 and PS4, after parameter expansion, as zsh does (see the user documentation on prompts).

prompt.transient_rprompt (transientrprompt)

Remove the right prompt (RPROMPT) from the screen when a command line is accepted, as zsh’s option does, so that it doesn’t stay in the scrollback.

glob.star (globstar)

**/ in a pattern matches any number of directories, as in zsh.

glob.bare_qualifiers (bareglobqual)

Parentheses at the end of a pattern hold zsh’s glob qualifiers, as in *(/) (directories) or *(.om[0]) (the newest file). See the documentation on extended globbing.

glob.null (nullglob)

A pattern that matches no file is removed, rather than left as it is.

glob.dots (globdots)

Patterns match names that start with . (but not . and ..), and **/ enters hidden directories.

glob.fail (nomatch)

A pattern that matches no file is an error (no matches found), as zsh’s NOMATCH and bash’s failglob.

glob.fail_all (cshnullglob)

Patterns that match no file are removed, but it is an error if none of the patterns of a command matches. glob.null wins over it, and it wins over glob.fail.

expand.braces (braceexpand)

Brace expansion, as in bash and zsh: f/{a,b} is f/a f/b, and {1..3} is 1 2 3 (also {01..10}, {10..1..3}, {a..e} and {1..$n}). It applies to the words of commands and for and the elements of arrays, before their other expansions, not to assignments. See the documentation on compatibility for where bash and zsh differ.

cd.auto (autocd)

A command that is only a directory’s name, with no arguments or redirections, changes to that directory, as in zsh. It applies only to commands read from standard input (as in an interactive shell), not to scripts or -c, and only when there is no command, function or executable file of that name. A relative name not starting with . or .. is looked for in the current directory, then in CDPATH.

pushd.auto, pushd.ignore_dups, pushd.silent

zsh’s autopushd, pushdignoredups and pushdsilent: cd pushes the previous directory onto the directory stack (and takes +n and -n); the new directory is removed from the stack after cd, pushd and popd, so that each is there once; pushd and popd don’t print the stack. See pushd.

editor.autosuggest (autosuggest)

In an interactive shell, show the rest of the newest command in the history that starts with the line typed, in grey after the cursor, as zsh-autosuggestions does. Right, End, Ctrl-F or Ctrl-E accept it, and Alt-F accepts its next word.

editor.no_highlight

Don’t colour the command line as it is typed (see style). The completion menu and autosuggestions keep their styles.

highlight.paths

Mark the arguments and redirection targets that name files that exist (style path), and the word under the cursor if it begins the name of one (path.prefix), as the command line is typed.

terminal.no_integration

Don’t tell the terminal where the prompts, command lines and command outputs are (OSC 133), nor the current directory (OSC 7), don’t make file names in error messages links (OSC 8), and leave the cursor’s shape alone in vi mode. See the user documentation on terminal integration.

vars.trace

Record where each variable is set, which where shows (see where). The changes of PATH, MANPATH, PS1, RPROMPT and RPS1 are all kept (up to 100), as with vars.trace_history. While it is on, the startup caches aren’t used. Use luish -o vars.trace to trace the startup files too.

vars.trace_history

As vars.trace, but keep the last 100 changes of every variable, with their values, for where -a.

vars.trace_after_startup

As vars.trace (or vars.trace_history, if it is on too), but only once the startup files have run: set in them or with -o, tracing starts before the first command, as if setopt vars.trace were typed at the first prompt. Startup is as fast as without tracing, with its caches, and what it set shows as set during startup.

startup.auto_cache

Cache whole startup files (those of rc.d and login.d), and config.toml with the plugins it enables, so that a new shell restores what they did instead of running them. Off, they run in every shell, and only their __luish_cache blocks are cached. It is read from config.toml (where [options.startup] auto_cache = true sets it) before rc.d, so setting it later has no effect until the next shell. See the user documentation on cached startup files.

The history options (see the user documentation on history):

history.ignore_space (histignorespace)

Don’t save a command that starts with a space or a tab. It stays in the history, to be recalled, until the next command replaces it.

history.reduce_blanks (histreduceblanks)

Replace runs of blanks in a command by one space before it goes into the history, except in quotes and here-documents.

history.save_no_dups (histsavenodups)

When the history file is trimmed, leave out commands that are repeated later in it.

history.inc_append (incappendhistory)

Append each command to the history file when it is run, rather than when the shell exits.

history.share (sharehistory)

As history.inc_append, and also read the commands that other shells have added to the history file, before each prompt.

history.expand (banghist, histexpand)

In an interactive shell, expand history references such as !!, !$ and ^old^new in the lines typed, as zsh and bash do (see the user documentation on history expansion).

history.verify (histverify)

With history.expand, put a line whose references were expanded back in the line editor, rather than running it.

Settings with a value, which are the shell variables in parentheses: setopt name=value sets the variable (a number must be a non-negative decimal number), and unsetopt name unsets it, which gives the default back. They aren’t listed by setopt or unsetopt without arguments.

history.file (HISTFILE)

The history file, by default $XDG_STATE_HOME/luish/history. An empty value means no file.

history.size (HISTSIZE)

How many commands the history keeps, 1000 by default.

history.save_size (SAVEHIST)

How many commands the history file keeps, by default as many as history.size.

Interactive shells also read these settings from ~/.config/luish/config.toml, where each table under options is a group, as in [options.history], a key directly under options is a setting by its own name. Its alias, bindkey and plugins tables define aliases, key bindings and the plugins to load (see the user documentation).

The exit status is 1 if an option doesn’t exist or can’t be changed (interactive and stdin), if a value is wrong or missing, if unsetopt is given a value, or if the variable of a setting is read-only; the other options given are still set. It is also 1, and nothing is set, if the group of -p doesn’t exist, and 2 for an invalid option or a missing group.

shift

shift [n]

Shift the positional parameters to the left.

$2 becomes $1, $3 becomes $2, and so on; n (by default 1) of them are removed. Shifting more than there are is an error.

shopt

shopt [-pqsu] [-o] [name...]

Set or show bash’s options.

This command is not in POSIX; it is bash’s, so that .bashrc lines and bash scripts that use it work. shopt -s name sets the option that does the same in luish, as setopt does, and shopt -u name unsets it:

autocd

cd.auto

dotglob

glob.dots

failglob

glob.fail

globstar

glob.star

histverify

history.verify

nullglob

glob.null

When both nullglob and failglob are on, nullglob wins, as in zsh (in bash, failglob does).

Some of bash’s options describe what luish always does, so they are always on: checkwinsize, cmdhist, expand_aliases, globasciiranges, histappend, inherit_errexit, interactive_comments, lithist, progcomp, promptvars, shift_verbose, sourcepath and xpg_echo. login_shell is on in a login shell and off otherwise. The others are always off, as luish doesn’t have them (such as extglob and nocaseglob). Setting an option that is always on, or unsetting one that is always off, does nothing. The opposite is an error.

-s

Set the options named (with names), or list those that are on.

-u

Unset the options named (with names), or list those that are off.

-o

The names are those of set -o (see set and setopt).

-p

List the options as the commands that set them: shopt -s name or shopt -u name, and with -o, set -o name or set +o name. The output can be read back with . or eval.

-q

Don’t list anything: the exit status tells whether the options named are all on.

Without -s or -u, or without names, shopt lists the options named, or all of them, as name on or name off.

The exit status is 0, except when an option named is off (when listing), 1 if a name doesn’t exist, if an option can’t be changed as asked, or if both -s and -u are given, and 2 for an invalid option.

style

style [-p]
style name [value...]
style -r name...
style --clear
style -c [scheme | dark light [default]]
style --detect
style --terminal-colors [on | off]
style -s scheme [name [value...] | -r name... | -i [parent] | --delete]
style -d name value... | -d -r name...

Show or change the line editor’s styles and colour scheme.

A style is a name, such as keyword or command.unknown, and a value: words that give a colour, a background colour and attributes. The names are dotted, and a style that is not set takes what it doesn’t say from its parent (command.alias from command). See the user documentation on syntax highlighting for the names and values, and on colour schemes. Prompts also use the styles, with %[style:name] (when setopt prompt.percent is on).

With no arguments, style lists every name with the style it has in the scheme in use. With a name, it shows that style, and where each part of it comes from. With a name and a value, it sets the style, over what the colour scheme gives; the value’s words may be one argument or several:

style command.unknown bold red
style comment 'italic bright-black'

-r removes the styles of the names given, which then come from the colour scheme again. --clear removes all of them and chooses no scheme, so that nothing is styled, as a starting point. -p prints commands that recreate the schemes defined, the scheme chosen and the styles set.

-c with a scheme chooses it. With two, it chooses the first if the terminal’s background is dark and the second if it is light, and with a third, that one if the background is not known (otherwise the first). The background is known from $LUISH_BACKGROUND (dark or light), which the shell sets before its first prompt from $COLORFGBG (which some terminals set) or else by asking the terminal for its background colour. --detect asks the terminal again, after its colours have changed, and fails if it doesn’t tell. -c alone lists the schemes, marking the one in use.

-s defines or changes a scheme, as a [colorscheme.NAME] table in config.toml does: with a name and a value, it sets the style in the scheme (defining it if it isn’t), with a name alone it shows it, and with nothing else it lists the scheme. -r removes styles from the scheme, -i sets the scheme it inherits from (none if empty), and --delete removes the scheme (a built-in one goes back to how it was).

A scheme’s names terminal.background, terminal.foreground, terminal.cursor and terminal.palette are the terminal’s own colours, which the shell sets while the scheme is in use and puts back afterwards (as a scheme’s terminal table in config.toml gives them): each value is a #rrggbb colour, and terminal.palette up to 16, for colours 0 to 15 of the terminal’s palette.

--terminal-colors off (or --terminal-colours) keeps the terminal’s own colours whatever the scheme says, as terminal-colors = false in the [style] table of config.toml does, and puts back those the shell set; on sets them again, and with neither, it shows which is in effect.

-d sets or removes a default, as the [style] table of a plugin’s plugin.toml does: under the colour scheme.

The status is 1 for an unknown name (with a suggestion if one is close), a bad value or a scheme that doesn’t exist, and 2 for a bad option.

test, [

test expression
[ expression ]

Evaluate a conditional expression.

The exit status is 0 if the expression is true, 1 if it is false and 2 on an error. With one argument, the expression is true if it is not empty. [[ ... ]] is a reserved word, not this command, with more operators (see “Shell language extensions” in the Usage page of the documentation).

-e file, -f file, -d file

file exists; is a regular file; is a directory. Also -b (block device), -c (character device), -h or -L (symbolic link), -p (named pipe) and -S (socket).

-r file, -w file, -x file

file is readable; writable; executable (or searchable).

-s file

file exists and is not empty. Also -u, -g, -k (set-user-ID, set-group-ID and sticky bits) and -O, -G (owned by the user, group).

-t fd

File descriptor fd is a terminal.

file1 -nt file2, file1 -ot file2, file1 -ef file2

file1 is newer; older; the same file. A file that exists is newer than one that doesn’t.

-n string, -z string

string is not empty; is empty.

s1 = s2, s1 != s2, s1 < s2, s1 > s2

The strings are equal; different; sorted before; sorted after. == is the same as =, as in zsh and bash.

n1 -eq n2

The integers are equal. Also -ne, -lt, -le, -gt and -ge.

! expr, expr1 -a expr2, expr1 -o expr2, ( expr )

Not; and; or; grouping. Parentheses must be quoted from the shell. For anything complicated, test ... && test ... is clearer.

times

times

Show the CPU time used by the shell and its children.

The first line is the user and system time of the shell, the second that of the commands it has run (once they have finished).

trap

trap [action] signal...
trap - signal...
trap

Run a command when the shell receives a signal or exits.

action is run (as with eval) when one of the signals arrives. An empty action ignores the signals, and - restores their default behaviour (as does leaving out the action, when there is one signal or the first one is a number). Signals are named without SIG (INT, TERM, HUP…) or by number; EXIT or 0 is the shell exiting. Without arguments, trap lists the traps as commands that can be read back.

Traps are reset in subshells, except ignored signals. Signals that were ignored when a shell that isn’t interactive started can’t be trapped.

tmp=$(mktemp) && trap 'rm -f "$tmp"' EXIT

true

true

Do nothing, successfully (exit status 0).

true ignores its arguments.

type

type name...

Describe how each name would be run as a command.

Each name is shown as a keyword, an alias, a special built-in, a function, a built-in, or the path of a program (a “tracked alias” if the shell has remembered its path). The exit status is 127 if one of them isn’t found.

typeset

typeset [-aAgilruUx] [+ilruUx] name[=value]... name=(value...)...
typeset -p [-aAilruUx] [name...]
typeset -f|+f [name...]
declare ...

Declare variables and set their attributes.

Not POSIX; as in zsh and bash. Each variable is set to value, if one is given, and gets the attributes given as options (+ removes one). In a function, the variables are local to it (unless -g is given), and start unset, unlike with local, which keeps the value. Outside a function, typeset name declares name without setting it. Arguments that look like assignments are expanded as assignments are, as for export. declare is another name for typeset.

-a

Make the variables arrays: a string becomes an array of one element, and a variable that isn’t set becomes an empty array.

-A

Make the variables associative arrays: a string becomes the value at key 0, and a variable that isn’t set becomes an empty associative array. Their values are given as name=([key]=value...), or as pairs of keys and values, name=(key value...). An array can’t become an associative one, nor the other way around.

-f

Print the definitions of the functions named (all of them without names), as text that can be read back. +f prints only their names. The status is 1 if a name isn’t a function. It takes no variable attributes.

-g

In a function, change the variables outside it rather than make local ones.

-i

Give the variables the integer attribute: each value assigned to them (also by read, for or local) is evaluated as an arithmetic expression, and stored in decimal, and name+=expr adds. A value they already have is evaluated too. For an array, each element is evaluated. An error in the expression is an error of the assignment. The attribute is removed by +i and unset, and doesn’t apply to a local made by local or to an assignment before a command (x=1+1 cmd).

-l

Convert the values assigned to the variables (each element of an array) to lower case, as -i evaluates them: ASCII letters only. -l and -u replace each other.

-p

Print the variables named, or all those that have the attributes given (all of them without other options), as typeset commands that can be read back. Without names or other options, typeset does the same. Special parameters such as path, pipestatus and RANDOM are printed with their current value when named, but listed only if they have attributes.

-r

Make the variables read-only (see readonly). A read-only variable can’t lose the attribute, but a local one hides it until the function returns.

-u

Convert the values assigned to upper case, as -l does to lower case.

-U

Keep only the first of equal elements in arrays (zsh), whenever they are assigned. On path, this removes repeated directories from PATH (so does -U on PATH when it is assigned).

-x

Export the variables (see export). +x stops exporting them.

f() {
    typeset -a files=(*.txt)
    typeset -gi count=${#files[@]}
    count+=1
    typeset -A seen=([.]=1 [..]=1)
}
typeset -U path
path=(~/bin "${path[@]}")

ulimit

ulimit [-H | -S] [-a | -tfdscmlpnvwr] [limit]

Show or set limits on resources (such as memory or files).

With a limit (a number, or unlimited), set it; otherwise show it. By default, a new limit sets both the soft limit and the hard limit, and the soft limit is shown.

-H, -S

Only the hard limit (which can’t be raised again, except by root); only the soft limit.

-a

Show all the limits.

-f

File size, in blocks of 512 bytes (the default).

-t

CPU time, in seconds.

-d, -s, -m, -l, -v

Data segment, stack, resident memory, locked memory and address space, in kilobytes.

-c

Core file size, in blocks of 512 bytes.

-n, -p, -w, -r

Open files; processes; file locks; real-time priority.

umask

umask [-S] [mode]

Show or set the file mode creation mask.

The permissions in the mask are removed from the files and directories that the shell and its children create. mode is octal (umask 022) or symbolic (umask u=rwx,g=rx,o=, which names the permissions to allow). Without mode, the mask is shown in octal.

-S

Show the mask in symbolic form (u=rwx,g=rx,o=rx).

unalias

unalias [-ms] name...
unalias -a [-s]

Remove aliases.

-a removes all regular and global aliases. With -s, the names are suffixes, and -as removes all suffix aliases. With -m, the names are patterns (quote them), and every alias that matches is removed. The exit status is 1 if one of the names isn’t an alias, or if no alias matches with -m.

unset

unset [-v] name... 'name[index]'... 'name[key]'...
unset -f name...

Remove variables or functions.

-v

Remove variables (the default). Read-only variables can’t be removed.

-f

Remove functions.

Removing something that doesn’t exist is not an error.

unset 'a[i]' (quoted, since [ is a glob character) makes element i of the array a empty, as in zsh; the array keeps its length. unset 'a[@]' removes the whole array. unset 'h[key]' removes a key of the associative array h.

vared

vared [-Aacegh] [-p prompt] [-r rprompt] [-M keymap] [-m keymap] name

Edit the value of a variable with the line editor.

vared puts the value of name on a line of its own and lets you edit it with the same keys as a command line; Enter sets the variable to the edited text. It is zsh’s vared:

vared PATH
vared -p 'Commit message: ' -c msg

The line isn’t a command, so it isn’t highlighted and has no autosuggestions. Tab completes as it would in a command’s argument.

An array is shown as its elements separated by the first character of IFS (a space by default), with a backslash before each character of IFS and each backslash in them. The edited text is split back into elements at the characters of IFS that no backslash quotes; a backslash before any other character stays. Blanks around a separator count as one, so with blanks as the separators (as by default) an empty element is lost, as in zsh; between two other separators (IFS=:) it is kept. An associative array is shown as its keys and values in turn, and the edited text must have pairs of them.

name[i] edits an element of an array (name[key] one of an associative array), which is added if there is none.

-c

Create the variable if it is unset. With -c, it becomes a string, or an array with -a, or an associative array with -A, replacing a variable of another type.

-a, -A

With -c: make the variable an array, or an associative array.

-p prompt

Show prompt before the value, with its % sequences expanded as in PS1 (see setopt prompt.percent), whether or not that option is on.

-r rprompt

Show rprompt at the right edge, as RPROMPT.

-h

Let the history be used (Up, Ctrl-R, …). Without it, there is none.

-e

Make Ctrl-D on an empty line give up, with status 1. Without -e it does nothing.

-M keymap

Edit with emacs or viins (vi) keys, or main, the shell’s.

-m keymap

Only vicmd, vi’s command mode, which vi editing always uses.

-g

Accepted and ignored (zsh’s quiets warnings luish doesn’t give).

zsh’s -i and -f (widgets to run first and last) and -t (another terminal) are not supported.

Ctrl-C gives up as it does at the prompt: the variable is left as it was, and the rest of the command line isn’t run, unless INT is trapped.

vared is a built-in only in interactive shells (and their subshells), so that scripts find the same commands as they do in dash. __luish_internal vared is the same command in any shell whose standard input is a terminal.

The status is 0 if the variable was set; 1 if the editing was given up, the variable doesn’t exist (without -c) or is read-only, there is no terminal, or for a usage error.

wait

wait [job | pid...]

Wait for background jobs to finish.

Without arguments, wait waits for all background jobs, and its exit status is 0. With arguments, it waits for each of them in turn (a process ID, or a job as described in help jobs), and the exit status is that of the last one, or 127 if it isn’t a child of the shell.

A signal that has a trap interrupts the wait: the trap runs, and the exit status is 128 plus the signal number.

where

where [-a] [name...]

Show where variables were set.

where answers from what variable tracing recorded, so it needs setopt vars.trace (or vars.trace_history), best turned on from the start with luish -o vars.trace. For each name, it prints one line with the variable’s value and where it was set: the file and line, and the function that ran, or the prompt, the -c command or standard input.

$ where PATH EDITOR
PATH was set to "/home/me/bin:/usr/bin" in ~/.config/luish/rc.d/path.lsh:3
EDITOR was set to "vi" in ~/.my-script.sh:123, in function setup

A variable can also have come from the environment (was inherited from the environment), been set by luish as it started (such as IFS and PS1), been set during startup (when tracing started after it, with vars.trace_after_startup), or been set before tracing began. After a function with the variable local returns, or after a command with a temporary assignment (X=1 cmd), where shows where the value put back was set. path is PATH. Without names, where shows every variable that is set.

-a

Show every change recorded, oldest first and numbered, with the values set and values put back; the last is marked current state. With vars.trace this is the last change only, except for PATH, MANPATH, PS1, RPROMPT and RPS1, whose last 100 changes are kept; vars.trace_history keeps the last 100 changes of every variable. A first line tells how many older changes were dropped, and a blank line separates variables.

$ where -a PATH
[1] PATH was inherited from the environment as
    "/usr/bin:/bin"
[2 - current state] PATH was set to
    "/home/me/bin:/usr/bin:/bin"
    in ~/.config/luish/rc.d/path.lsh:3

Values are shown in double quotes, or as $'...' if they have control characters; arrays are shown as ("a" "b"), and values longer than 4096 bytes are cut. A value too long to fit on the line (of the terminal, or 80 columns) goes on a line of its own, indented, and where it was set on the next; with -a, if one of a variable’s values does, they all do. On a terminal, names, values, files and functions are in colour, in the styles var, string, path, command.function and comment (see help style), unless $NO_COLOR is set.

where is a built-in of interactive shells, and of other shells while variables are traced; elsewhere __luish_internal where runs it. It is not zsh’s where, which lists every command a name finds (type shows the one that runs).

The status is 0 if every variable is set or has a recorded change, 1 if any isn’t set and has none, and 2 for a bad name or if tracing is off.