MKSH(1)
๐ MKSH(1) โ General Commands Manual ๐
okay bestie, this is the manual for mksh, the MirBSD Korn shell โ also answers to sh. no cap, she's a whole command interpreter. ๐
๐ธ NAME ๐ธ
mksh, sh โ MirBSD Korn shell
โจ SYNOPSIS โจ
mksh [-+abCefhiklmnprUuvXx] [-+o option] [-T [!]tty|-] [file [arg1 ...]]
mksh [-+abCefhiklmnprUuvXx] [-+o option] [-T [!]tty|-] -c cmd [arg0 ...]
mksh [-+abCefhiklmnprUuvXx] [-+o option] [-T [!]tty|-] -s [arg1 ...]
builtin-name [argument ...]
๐ DESCRIPTION ๐
mksh is a command interpreter, and she's here for both interactive use and shell script use. Her command language is a superset of both sh(C) and POSIX shell language, and she's largely compatible with the original Korn shell. Sometimes this manual page will give you scripting advice; while it sometimes takes portable shell scripting or various standards into account, all information is first and foremost presented with mksh in mind and should be taken as such. periodt.
๐ฆ I use Android, OS/2, etc. so what...? ๐ฆ
Please refer to: http://www.mirbsd.org/mksh-faq.htm#sowhatismksh
๐ Invocation ๐
Most builtins can be called directly โ for example if a link or symlink(7) points to mksh, or if argv[0] is set correspondingly. But bestie, this does not make sense for, or work properly with, all built-in utilities though. Debug builds can also be invoked as --unparse to display the parse tree of each command before running it. iconic.
The options are as follows:
-cโmkshwill execute the command(s) contained incmd, setting$0toarg0(if present),$1to the next argument, etc. If compiled with-DMKSH_MIDNIGHTBSD01ASH_COMPATand in-o shmode, a--argument directly followingcmdis ignored for compatibility with the legacy FreeBSDsh; this is deprecated and may go away in the future.-iโ Interactive shell. A shell that reads commands from standard input is โinteractiveโ if this option is used or if both standard input and standard error are attached to atty(4). An interactive shell has job control enabled, ignores theSIGINT,SIGQUITandSIGTERMsignals, and prints prompts before reading input (see thePS1andPS2parameters). It also processes theENVparameter or themkshrcfile (see below). For non-interactive shells, thetrackalloption is on by default (see thesetcommand below).-lโ Login shell. If the name the shell is called as (i.e.argv[0]) or its basename begins with a dash (hyphen-minus)-or if this option is given, the shell is a โlogin shellโ; see โStartup filesโ below.-pโ Privileged shell. A shell is โprivilegedโ if the real user ID fromgetuid(2)or group ID fromgetgid(2)does not match the effective user ID or group ID. Clearing the privileged option causes the shell to set its effective user ID and group ID to its initial real user ID and group ID, respectively. For further implications, seeset -pand โStartup filesโ. If the shell is privileged and this flag is not set explicitly on invocation, nor during processing the startup files, the โprivilegedโ flag is cleared automatically afterwards.-rโ Restricted shell. A shell is โrestrictedโ if the basename the shell is called with, after dash removal, begins withror if this option is used. The following restrictions come into effect after the shell processes any profile andENVfiles:- Command names cannot be specified with pathnames, either absolute or relative; the
-pflag of thecommandbuilt-in utility is not usable. TheENV,PATHandSHELLparameters cannot be changed. - The current location is fixed: the
cdbuiltin is disabled. - Redirections that create files, i.e.
>,>|,>>and<>, cannot be used, and theHISTFILEparameter cannot be changed.
- Command names cannot be specified with pathnames, either absolute or relative; the
-sโmkshwill read and execute commands from standard input; all non-option arguments are assigned to the positional parameters.-T -โ Detach from the controlling terminal, return immediately (daemonise).-T [!]nameโ Spawnmkshon thetty(4)device given. The pathsname,/dev/ttyCnameand/dev/ttynameare attempted in order. Ifnameis prefixed with an exclamation mark (!), wait for the spawned shell to return, report its exit status or terminating signal visually. Exit 0 if spawned.
In addition to the above, the flags [-+abCefhkmnUuvXx] and [-+o option], respectively for single-letter and long options, as described for the set built-in utility, can be used on the command line.
If neither the -c nor the -s options are specified, mksh will read and execute commands as if the -s flag was passed iff the file argument is absent or -; otherwise, it sets $0 to file and reads commands from it. Further arguments arg1 ... are assigned to positional parameters.
The exit status of the shell is 127 if the file specified on the command line could not be opened, or non-zero if a fatal error occurred during execution of the script. Otherwise, the errorlevel is that of the last command executed, 0 if no command was executed.
๐ท Startup files ๐ท
For the actual location of these files, see โFILESโ. A login shell processes the system profile first. A privileged shell then processes the suid profile. A non-privileged login shell processes the user profile next. A non-privileged interactive shell checks the value of the ENV parameter after subjecting it to parameter, command, arithmetic and tilde (~) substitution; if unset or empty, the user mkshrc profile is processed; otherwise, if a file whose name is the substitution result exists, it is processed; non-existence is silently ignored. A privileged shell then drops privileges if neither was the -p option given on the command line nor set during execution of the startup files.
๐ง Command syntax ๐ง
The shell begins parsing its input by removing any backslash-newline combinations, then breaking it into words. Words (which are sequences of characters) are delimited by unquoted whitespace characters (space, tab and newline) or meta-characters (<, >, |, ;, (, ) and &). Aside from delimiting words, spaces and tabs are ignored, while newlines usually delimit commands. The meta-characters are used in building the following tokens: <, <&, <<, <<<, >, >&, >>, &>, etc. are used to specify redirections (see โInput/output redirectionโ below); | is used to create pipelines; |& is used to create co-processes (see โCo-processesโ below); ; is used to separate commands; & is used to create asynchronous pipelines; && and || are used to specify conditional execution; ;;, ;& and ;| are used in case statements; (( ... )) is used in arithmetic expressions; and lastly, ( ... ) is used to create subshells.
Whitespace and meta-characters can be quoted individually using a backslash (\), or in groups using double (") or single (') quotes. Note that the following characters are also treated specially by the shell and must be quoted if they are to represent themselves: \, ", ', #, $, `, ~, {, }, *, ? and [. The first three of these are the above mentioned quoting characters (see โQuotingโ below); #, if used at the beginning of a word, introduces a comment โ everything after the # up to the nearest newline is ignored; $ is used to introduce parameter, command and arithmetic substitutions (see โSubstitutionโ below); ` introduces an old-style command substitution (see โSubstitutionโ below); ~ begins a directory expansion (see โTilde expansionโ below); { and } delimit csh(1)-style alternations (see โBrace expansionโ below); and finally, *, ? and [ are used in file name generation (see โFile name patternsโ below).
As words and tokens are parsed, the shell builds commands, of which there are two basic types: simple-commands, typically programmes that are executed, and compound-commands, such as for and if statements, grouping constructs and function definitions.
A simple-command consists of some combination of parameter assignments (see โParametersโ below), input/output redirections (see โInput/output redirectionsโ below) and command words; the only restriction is that parameter assignments come before any command words. The command words, if any, define the command that is to be executed and its arguments. The command may be a shell built-in command, a function or an external command (i.e. a separate executable file that is located using the PATH parameter; see โCommand executionโ below). Note that all command constructs have an exit status: for external commands, this is related to the status returned by wait(2) (if the command could not be found, the exit status is 127; if it could not be executed, the exit status is 126); the exit status of other command constructs (built-in commands, functions, compound-commands, pipelines, lists, etc.) are all well-defined and are described where the construct is described. The exit status of a command consisting only of parameter assignments is that of the last command substitution performed during the parameter assignment or 0 if there were no command substitutions.
Commands can be chained together using the | token to form pipelines, in which the standard output of each command but the last is piped (see pipe(2)) to the standard input of the following command. The exit status of a pipeline is that of its last command, unless the pipefail option is set (see there). All commands of a pipeline are executed in separate subshells; this is allowed by POSIX but differs from both variants of AT&T UNIX ksh, where all but the last command were executed in subshells; see the read builtin's description for implications and workarounds. A pipeline may be prefixed by the ! reserved word which causes the exit status of the pipeline to be logically complemented: if the original status was 0, the complemented status will be 1; if the original status was not 0, the complemented status will be 0.
Lists of commands can be created by separating pipelines by any of the following tokens: &&, ||, &, |& and ;. The first two are for conditional execution: cmd1 && cmd2 executes cmd2 only if the exit status of cmd1 is zero; || is the opposite โ cmd2 is executed only if the exit status of cmd1 is non-zero. && and || have equal precedence which is higher than that of &, |& and ;, which also have equal precedence. Note that the && and || operators are "left-associative". For example, both of these commands will print only "bar":
$ false && echo foo || echo bar
$ true || echo foo && echo bar
The <code>&</code> token = "go do your thing bestie, I'm not waiting up for you" energy. It makes the command before it run asynchronously โ like, the shell kicks it off but does NOT sit there waiting for it to finish. (Don't worry, she's still keeping receipts; she does track the status of async commands, peek "Job control" below ๐
). Now here's the โจimportantโจ bit: when an async command starts while job control is disabled (which is, like, most scripts), that command gets launched with the signals SIGINT and SIGQUIT ignored, and its input redirected from /dev/null โ except any redirections you literally spelled out in the asynchronous command itself win. Precedence, queen ๐.
The |& operator is a whole different vibe: it starts a co-process, which is just a special kind of asynchronous process (slide over to "Co-processes" below, iykyk).
ngl this part trips people up: a command must follow && and ||, but it does not have to follow &, |& or ;. And the exit status of a list? It's whatever the last command that executed returned โ except for asynchronous lists, where the exit status is just 0. periodt.
Compound commands get built out of these reserved words. Heads up: they're only recognised when they're unquoted and sitting as the first word of a command (so no sneaking parameter assignments or redirections in front of them, bestie):
case else function then ! (
do esac if time [[ ((
done fi in until {
elif for select while }
Now, in all the compound command descriptions below: any command list (we call it list) that's followed by a reserved word has to end with a semicolon, a newline, or a (syntactically correct) reserved word. Like, all of these are valid, no cap:
$ { echo foo; echo bar; }
$ { echo foo; echo bar<newline>}
$ { { echo foo; echo bar; } }
And this one? Not valid. Absolutely not. ๐ซ
$ { echo foo; echo bar }
๐ Compound commands ๐
case word in [[(] pattern [| pattern] ...) list <terminator>] ... esacโ thecasestatement tries to match word against a pattern you hand it, and the list attached to the first pattern that matches successfully gets executed. The patterns here work just like file name patterns, except the rules about.and/are dropped entirely. Tiny detail that bites people: any unquoted space before and after a pattern is stripped, so if you want a space inside a pattern you must quote it, fr. And both the word and the patterns go through parameter, command and arithmetic substitution, plus tilde substitution.
For historical reasons (auntie ksh era ๐) you can use open and close braces instead of in and esac, like: case $foo { (ba[rz]|blah) date ;; }
The list *<terminator>*s are:
;;โ terminate after the list.;&โ fall through into the next list.;|โ evaluate the remaining pattern-list tuples.
The exit status of a case statement is the exit status of the list that got executed; if no list runs, the exit status is zero.
for name [in word ...] ; do list; doneโ for every word in the word list you gave, the parameter name gets set to that word and list runs. The exit status of aforstatement is the last exit status of list; if list never executes at all, the exit status is zero. Skip theinand the positional parameters ($1,$2, etc.) get used instead โ and in that case use a newline instead of the semicolon;for portability, bestie. Historical flex: open and close braces work in place ofdoanddone, likefor i; { echo $i; }โ but that's not portable, so don't @ me.function name { list; }โ defines the function name (see "Functions" below ๐ธ). Important: all redirections specified after a function definition are performed whenever the function is executed, not when the definition itself runs. Big difference, remember it.name()command โ basically the same asfunction(see above and "Functions" below). Most amounts of space and tab after name get ignored, slay.function name() { list; }โ a bashism forname() { list; }(thefunctionkeyword is just ignored here, iconic).if list; then list; [elif list; then list;] ... [else list;] fiโ if the first list exits with status zero, the second list runs; otherwise the list after theelif, if there is one, runs with the same consequences. If all the lists after theifand theelifs fail (i.e. exit non-zero), then the list afterelseruns. The exit status of anifstatement is that of whatever non-conditional (not the first) list got executed; if no non-conditional list is executed, the exit status is zero.select name [in word ...]; do list; doneโselecthands you a whole automatic menu situation ๐. It prints an enumerated list of the specified words on standard error, followed by a prompt (PS3: normally#?). Then it reads a number from standard input corresponding to one of the enumerated words, sets name to the selected word (or unsets it if the selection isn't valid), setsREPLYto whatever was read (leading and trailing space stripped), and runs list. If you enter a blank line (i.e. zero or moreIFSoctets), the menu just reprints and list does not run.
When list finishes, the enumerated list prints again if REPLY is empty, then the prompt prints, and so on forever. This keeps going until an end-of-file is read, an interrupt is received, or a break statement is executed inside the loop. Exit status of a select statement is zero if a break statement was used to exit the loop, non-zero otherwise. Omit in word ... and the positional parameters get used. And for historical reasons, open and close braces may replace do and done, like: select i; { echo $i; }
time [-p] [pipeline]โ the "Command execution" section describes thetimereserved word. When it's not a reserved word, a builtin runs the passed command.until list; do list; doneโ works exactly likewhile(below), except the body list only executes while the exit status of the first list is non-zero.while list; do list; doneโ a pre-checked loop, bestie. Its body list runs as often as the exit status of the first list is zero. The exit status of awhilestatement is the last exit status of the list in the loop body; if the body never executes, the exit status is zero.[[ expression ]]โ similar to thetestand[ ... ]commands (described later), with these โจexceptionsโจ:- Field splitting and globbing are not performed on arguments.
- The
-a(AND) and-o(OR) operators are replaced with&&and||, respectively. - Operators (e.g.
-f,=,!) must be unquoted. - Parameter, command and arithmetic substitutions are performed as expressions are evaluated, and lazy expression evaluation is used for the
&&and||operators. Meaning: in the statement below,$(<foo)is evaluated if and only if the filefooexists and is readable:
$ [[ -r foo && $(<foo) = b*r ]]
- The second operand of
=and!=is a pattern (e.g. the comparison[[ foobar = f*r ]]succeeds). This even works indirectly, while quoting forces literal interpretation:
$ bar=foobar; baz='f*r' # or: baz='f+(o)b?r'
$ [[ $bar = $baz ]]; echo $? # 0
$ [[ $bar = "$baz" ]]; echo $? # 1
{ list; }โ compound construct; list is executed, but not in a subshell. Note that{and}are reserved words, not meta-characters. ๐(list)โ execute list in a subshell, forking. There is no implicit way to pass environment changes from a subshell back up to its parent. Sorry babe.(( expression ))โ the arithmetic expression expression gets evaluated; equivalent tolet "expression"in a compound construct. See theletcommand and "Arithmetic expressions" below.
๐ Quoting ๐
Quoting is how you stop the shell from treating characters or words specially. Three methods, take notes:
\quotes the character that follows it โ unless it's at the end of a line, in which case both the\and the newline get stripped.- A single quote (
') quotes everything up to the next single quote (this can span lines, no biggie). - A double quote (
") quotes all characters except$,\and`, up to the next unescaped double quote. Inside double quotes,$and`keep their usual meaning (i.e. parameter, arithmetic or command substitution) โ except no field splitting is carried out on the results of double-quoted substitutions, and the old-style form of command substitution has backslash-quoting for double quotes enabled.
And the backslash rules inside a double-quoted string? If a \ is followed by ", $, \ or `, only the \ is removed, i.e. the combination is replaced by that second character. If it's followed by a newline, both the \ and the newline are stripped. Otherwise, both the \ and the character following it stay unchanged.
Oh and this is a fun one: if a single-quoted string is preceded by an unquoted $, C style backslash expansion (see below) gets applied โ even single quote characters inside can be escaped and then they don't terminate the string. The expanded result is treated as any other single-quoted string. And if a double-quoted string is preceded by an unquoted $? The $ is simply ignored. that's it. ๐ฆ
๐ Backslash expansion ๐
Wherever backslashes get expanded, certain C and AT&T UNIX ksh or GNU bash style escapes get translated. These include \a, \b, \f, \n, \r, \t, \U########, \u#### and \v. For \U######## and \u####, the # means a hexadecimal digit (up to 4 or 8 of them); these translate a Universal Coded Character Set codepoint to UTF-8 (go read "CAVEATS" on UCS limitations, bestie ๐). Also, \E and \e both expand to the escape character.
In the print builtin mode, octal sequences must have the optional up-to-three octal digits # prefixed with the digit zero (\0###); hexadecimal sequences \x## are limited to up to two hexadecimal digits #; both octal and hexadecimal sequences convert to raw octets. And \% โ where % is none of the above โ translates to \% (backslashes are retained, periodt).
C style mode has opinions about your escapes, bestie, and honestly? Same. Let's break it down:
- raw octetโyielding octal sequences
\###must not have the one up to three octal digits prefixed with the digit zero - hexadecimal sequences
\x##greedily eat up as many hexadecimal digits#as they can and terminate with the first non-xdigit - below
\x100these produce raw octets; above, they're equivalent to\U# - the sequence
\c%, where%is any octet, translates to Ctrl-%โ so\c?becomes DEL, and literally everything else is bitwise ANDed with0x9F \%, where%is none of the above, translates to just%: backslashes are trimmed even before newlines ๐
โจ Aliases โจ
So there are two flavours of aliases: normal command aliases and tracked aliases. Two icons, different jobs ๐ซถ
Command aliases are normally used as a short hand for a long or often used command. The shell expands command aliases (i.e. substitutes the alias name for its value) when it reads the first word of a command. An expanded alias is re-processed to check for more aliases. If a command alias ends in a space or tab, the following word is also checked for alias expansion. And the alias expansion process stops when:
- a word that is not an alias is found,
- a quoted word is found, or
- an alias word that is currently being expanded is found.
Aliases are specifically an interactive feature: while they do happen to work in scripts and on the command line in some cases, aliases are expanded during lexing, so their use must be in a separate command tree from their definition; otherwise, the alias will not be found. Noticeably, command lists (separated by semicolon, in command substitutions also by newline) may be one same parse tree. ๐
The following command aliases are defined automatically by the shell:
autoload='\\builtin typeset -fu'
functions='\\builtin typeset -f'
hash='\\builtin alias -t'
history='\\builtin fc -l'
integer='\\builtin typeset -i'
local='\\builtin typeset'
login='\\builtin exec login'
nameref='\\builtin typeset -n'
nohup='nohup '
r='\\builtin fc -e -'
type='\\builtin whence -v'
Tracked aliases let the shell remember where it found a particular command. The first time the shell does a path search for a command that is marked as a tracked alias, it saves the full path of the command. The next time the command is executed, the shell checks the saved path to see that it's still valid, and if so, avoids repeating the path search. Tracked aliases can be listed and created using alias -t. Note that changing the PATH parameter clears the saved paths for all tracked aliases ๐ญ. If the trackall option is set (i.e. set -o trackall or set -h), the shell tracks all commands. This option is set automatically for non-interactive shells. For interactive shells, only the following commands are automatically tracked: cat(1), cc(1), chmod(1), cp(1), date(1), ed(1), emacs(1), grep(1), ls(1), make(1), mv(1), pr(1), rm(1), sed(1), sh(1), vi(1) and who(1).
โจ Substitution โจ
The first step the shell takes in executing a simple-command is to perform substitutions on the words of the command. There are three kinds of substitution: parameter, command and arithmetic. No cap, just three:
- Parameter substitutions, described in detail in the next section, take the form
$nameor${name...} - Arithmetic substitutions take the form
$((expression)) - Command substitutions take the form
$(command)or (deprecated)`command`or (executed in the current environment)${ command;}, and they evaluate to the output of command with any trailing newlines stripped. The latter form requires a space, tab or newline after the opening brace and that the closing brace be recognised as a keyword (i.e. is preceded by a newline or semicolon).
Those ${ command;} guys are also called funsubs (function substitutions) and they behave similar to functions in that shell options are shared and local and return work โ though, in contrast to valsubs (see below), exit does not terminate the parent shell, for compatibility with AT&T UNIX ksh93. ๐
Another variant of substitution are the valsubs (value substitutions) ${|command;} which are also executed in the current environment, like funsubs, but share their I/O with the parent. Instead, they evaluate to whatever the, initially empty, expression-local variable REPLY is set to within the commands; exit affects the parent like in a function call. Iconic behaviour honestly.
If a substitution appears outside of double quotes, the results of the substitution are generally subject to word or field splitting according to the current value of the IFS parameter. The IFS parameter specifies a list of octets which are used to break a string up into several words; any octets from the set space, tab and newline that appear in the IFS octets are called โIFS whitespaceโ. Sequences of one or more IFS whitespace octets, in combination with zero or one non-IFS whitespace octets, delimit a field. As a special case, leading and trailing IFS whitespace is stripped (i.e. no leading or trailing empty field is created by it); leading or trailing non-IFS whitespace does create an empty field. ๐ซ
Example: If IFS is set to โ<space>:โ and VAR is set to โ<space>A<space>:<space><space>B::Dโ, the substitution for $VAR results in four fields: โAโ, โBโ, โโ (an empty field) and โDโ. Note that if the IFS parameter is set to the empty string, no field splitting is done; if it is unset, the default value of space, tab and newline is used.
Also, note that the field splitting applies only to the immediate result of the substitution. Using the previous example, the substitution for $VAR:E results in the fields: โAโ, โBโ, โโ and โD:Eโ, not โAโ, โBโ, โโ, โDโ and โEโ. This behaviour is POSIX compliant but incompatible with some other shell implementations which do field splitting on the word which contained the substitution or use IFS as a general whitespace delimiter.
The results of substitution are, unless otherwise specified, also subject to brace expansion and file name expansion (see the relevant sections below).
A command substitution of the regular (comsub), deprecated, funsub or valsub form is replaced by the output generated by the specified command, which is run in a subshell โ except for the funsub and valsub types which run in the current execution environment. For $(command), ${ command;} and ${|command;} forms, normal quoting rules are used when command is parsed; however, for the deprecated `command` form, a \ followed by any of $, ` or \ is stripped (as is " when the substitution is part of a double-quoted string); a backslash followed by any other character is unchanged. As a special case in command substitutions, a command of the form <file is interpreted to mean substitute the contents of file, so that $(<foo) has the same effect, if foo is readable, as $(cat foo) but is much more performant. ๐ฅ
Heads up bestie ๐ญ some shells do not use a recursive parser for command substitutions, leading to failure for certain constructs; to be portable, use as workaroundx=$(cat) <<\EOF(or the newline-keepingx=<<\EOFextension) instead to merely slurp the string. IEEE Std 1003.1 (โPOSIX.1โ) recommends usingcasestatements of the formx=$(case $foo in (bar) echo $bar ;; (*) echo $baz ;; esac)instead, which would work but not serve as example for this portability issue.
x=$(case $foo in bar) echo $bar ;; *) echo $baz ;; esac)
# above fails to parse on old shells; below is the workaround
x=$(eval $(cat)) <<\EOF
case $foo in bar) echo $bar ;; *) echo $baz ;; esac
EOF
Arithmetic substitutions are replaced by the value of the specified expression. For example, the command print $((2+3*4)) displays 14. See โArithmetic expressionsโ for a description of an expression. Math ate, fr fr. ๐งฎโจ
โจ Parameters โจ
Parameters are shell variables; they can be assigned values, and their values can be accessed using a parameter substitution. A parameter name is either one of the special single punctuation character or positional parameters described below, or a letter followed by zero or more letters, digits or underscores. The latter form can be accessed as array by appending an index of the form [expr] (in which expr is an arithmetic expression). Array indices range from 0 to 4294967295 (2^32-1), inclusive, in mksh. Slay.
Parameter substitutions take the form $name, ${name} or ${name[expr]} where name is a parameter name. Substitutions of an array in scalar context, i.e. without an expr in the latter form mentioned above, expand the element with the key โ0โ. Substitution of all array elements with ${name[*]} and ${name[@]} works equivalent to $* and $@ for positional parameters. If substitution is performed on a parameter (or an array parameter element) that is not set, an empty string is substituted โ unless the nounset option (set -u) is set, in which case an error occurs. โ ๏ธ
Parameters can be assigned values in a number of ways. Bestie, there's a whole menu:
- First, the shell implicitly sets some parameters like โ#โ, โPWDโ and โ$โ; this is the only way the special single character parameters are set.
- Second, parameters are imported from the shell's environment at startup.
- Third, parameters can be assigned values on the command line: for example,
FOO=barsets the parameter โFOOโ to โbarโ; multiple parameter assignments can be given on a single command line and they can be followed by a simple-command, in which case the assignments are in effect only for the duration of the command (such assignments are also exported; see below for the implications of this). Note that both the parameter name and the=must be unquoted for the shell to recognise a parameter assignment. The constructFOO+=bazis also recognised; the old and new values are string-concatenated with no separator. - Fourth, it's with the
export,readonlyandtypesetcommands; see their descriptions in the โCommand executionโ section. - Fifth,
forandselectloops set parameters as well as thegetopts,readandset -Acommands. - Lastly, parameters can be assigned values using assignment operators inside arithmetic expressions (see โArithmetic expressionsโ below) or using the
${name=value}form of the parameter substitution (see below).
Parameters with the export attribute (set using the export or typeset -x commands, or by parameter assignments followed by simple commands) are put in the environment (see environ(7)) of commands run by the shell as name=value pairs. When the shell starts up, it extracts parameters and their values from its environment, setting the export attribute for those.
Modifiers can be applied to the ${name} form of parameter substitution:
${name:-word}โ if name is set and not empty, it is substituted; otherwise, word is substituted. ๐${name:+word}โ bestie, ifnameis set and not empty,wordgets substituted in. Otherwise? Nothing. Nada. Empty vibes only โจ${name:=word}โ ifnameis set and not empty, it gets substituted. If not,wordgets assigned to it, and then the resulting value ofnameis what you get. It's giving "assign and deliver" ๐${name:?word}โ ifnameis set and not empty, it's substituted. If not,wordis printed on standard error (preceded byname:) and an error occurs โ which normally means your shell script, function, or a script sourced using the.built-in terminates. Ifwordis omitted, the stringparameter null or not setis used instead.
ok so heads up for ALL of the above, bestie:wordis actually considered quoted, and special parsing rules apply. Also the parsing rules differ depending on whether the expression is double-quoted:wordthen uses double-quoting rules, except for the double quote itself (") and the closing brace, which โ if backslash escaped โ gets quote removal applied. iykyk ๐ซถ
In the modifiers above, the : can be omitted, and in that case the conditions only depend on name being set (as opposed to set and not empty). If word is needed, parameter, command, arithmetic and tilde substitution are performed on it; if word isn't needed, it is not evaluated. no wasted energy periodt ๐
The following forms of parameter substitution can also be used:
${#name}โ the number of positional parameters ifnameis*,@or not specified at all; otherwise it's the length (in characters ๐) of the string value of parametername.${#name[*]}${#name[@]}โ the number of elements in the arrayname.${%name}โ the width (in screen columns) of the string value of parametername, or-1if${name}contains a control character. ๐${!name}โ the name of the variable referred to byname. This will benameexcept whennameis a name reference (bound variable), created by thenamerefcommand (which is an alias fortypeset -n). Also,namecannot be one of most special parameters (see below ya girl's list ๐ซถ).${!name[*]}${!name[@]}โ the names of indices (keys) in the arrayname.${name#pattern}${name##pattern}โ ifpatternmatches the beginning of the value of parametername, the matched text is deleted from the result of substitution. A single#gives you the shortest match, and two of them (##) give you the longest match. slay โ๏ธ${name%pattern}${name%%pattern}โ like${...#...}but it deletes from the end of the value. back it up bestie ๐ฆ${name/pattern/string}${name/#pattern/string}${name/%pattern/string}${name//pattern/string}โ the longest match ofpatternin the value of parameternameis replaced withstring(deleted ifstringis empty; the trailing slash (/) may be omitted in that case). A leading slash followed by#or%causes the pattern to be anchored at the beginning or end of the value, respectively. Empty unanchored patterns cause no replacement. A single leading slash or a pattern that matches the empty string causes the replacement to happen only once; two leading slashes cause all occurrences of matches in the value to be replaced. Heads up though โ this may be slow on long strings ๐${name@/pattern/string}โ the same as${name//pattern/string}, EXCEPT that bothpatternandstringare expanded anew for each iteration. Use withKSH_MATCH. โจ${name:pos:len}โ the firstlencharacters ofname, starting at positionpos, are substituted. Bothposand:lenare optional. Ifposis negative, counting starts at the end of the string; if it's omitted, it defaults to0. Iflenis omitted or greater than the length of the remaining string, all of it is substituted. And bothposandlenare evaluated as arithmetic expressions ๐งฎ${name@#}โ the hash (using the BAFH1-0 algorithm) of the expansion ofname. This is also used internally for the shell's hashtables. no cap, it's the same machinery underneath ๐${name@Q}โ a quoted expression safe for re-entry, whose value is the value of thenameparameter, is substituted.${name@^}โ the value ofnamein extended caret notation, with both caret (^) and backslash (\) backslash-escaped to avoid ambiguity.
also quick note bestie:patternmay need extended globbing pattern (@(...)), single ('...') or double ("...") quote escaping โ unless-o shis set. ๐
โจ the special parameters โจ (they're literally built different)
The following special parameters are implicitly set by the shell and cannot be set directly using assignments. they're the main characters of the parameter world, you don't assign to them, they assign to you ๐
!โ process ID of the last background process started. If no background processes have been started, the parameter is not set. ๐ซฅ#โ the number of positional parameters ($1,$2, etc.).$โ the PID of the shell, or, if it's a subshell, the PID of the original shell.
โ ๏ธ WARNING โ ๏ธ do NOT use this mechanism for generating temporary file names, bestie, i'm literally begging ๐ญ see mktemp(1) instead. fr fr.
-โ the concatenation of the current single letter options (see thesetcommand below for a list of options).?โ the exit status of the last non-asynchronous command executed. If the last command was killed by a signal,$?is set to128plus the signal number โ but at most255. ๐0โ the name of the shell, determined like this: the first argument tomkshif it was invoked with the-coption and arguments were given; otherwise the file argument, if it was supplied; or else the name the shell was invoked with (i.e.argv[0]).$0is also set to the name of the current script, or to the name of the current function if it was defined with thefunctionkeyword (i.e. a Korn shell style function). she knows who she is ๐1 .. 9โ the first nine positional parameters that were supplied to the shell, function, or script sourced using the.("dot") builtin. Further positional parameters may be accessed using${number}. ๐ง*โ all positional parameters (except0), i.e.$1,$2,$3, ... . If used outside of double quotes, parameters are separate words (which are subjected to word splitting); if used within double quotes, parameters are separated by the first character of theIFSparameter (or the empty string ifIFSis unset). ๐ธ@โ same as$*, unless it's used inside double quotes, in which case a separate word is generated for each positional parameter. If there are no positional parameters, no word is generated."$@"can be used to access arguments, verbatim, without losing empty arguments or splitting arguments with spaces (IFS, actually). literally the icon of safe argument passing ๐ซถ
๐ the parameters the shell sets and/or uses ๐
These are set and/or used by the shell:
_โ (underscore) when an external command is executed by the shell, this parameter is set in the environment of the new process to the path of the executed command. And in interactive use, this parameter is also set in the parent shell to the last word of the previous command. ๐BASHPIDโ the PID of the shell or subshell.CDPATHโ likePATH, but used to resolve the argument to thecdbuilt-in command. Note that ifCDPATHis set and does not contain.or an empty string element, the current directory is not searched. Also, thecdbuilt-in command will display the resulting directory when a match is found in any search path other than the empty path. ๐บ๏ธCOLUMNSโ set to the number of columns on the terminal or window. If never unset and not imported, always set dynamically; unless the value as reported bystty(1)is non-zero and sane enough (minimum is12x3), defaults to80; similar forLINES. This parameter is used by the interactive line editing modes and by theselect,set -oandkill -lcommands to format information columns. Importing from the environment or unsetting this parameter removes the binding to the actual terminal size in favour of the provided value. ๐ENVโ if this parameter is found to be set after any profile files are executed, the expanded value is used as a shell startup file. It typically contains function and alias definitions. ๐EPOCHREALTIMEโ time since the epoch, as returned bygettimeofday(2), formatted as decimaltv_secfollowed by a dot (.) andtv_usecpadded to exactly six decimal digits. โฐEXECSHELLโ if set, this parameter is assumed to contain the shell that is to be used to execute commands thatexecve(2)fails to execute and which do not start with a#!shellsequence.FCEDITโ the editor used by thefccommand (see below). โ๏ธFPATHโ likePATH, but used when an undefined function is executed (or when a command cannot be found usingPATH) to locate the function definition file. See "Functions" below. ๐ฆHISTFILEโ the name of the file used to store command history. When assigned to or unset, the file is opened, history is truncated then loaded from the file; subsequent new commands (possibly consisting of several lines) are appended once they successfully compiled. Also, several invocations of the shell will share history if theirHISTFILEparameters all point to the same file. ๐ฏ
Note: ifHISTFILEis unset or empty, no history file is used. This is different from AT&T UNIXksh. ๐จ
HISTSIZEโ the number of commands normally stored for history. The default is2047. The maximum is65535. ๐HOMEโ the default directory for thecdcommand and the value substituted for an unqualified~(see "Tilde expansion" below). ๐IFSโ internal field separator, used during substitution and by thereadcommand, to split values into distinct arguments; normally set to space, tab and newline. See "Substitution" above for details. โ๏ธ
Note: this parameter is not imported from the environment when the shell is started. ๐
KSHEGIDโ the effective group id of the shell at startup.KSHGIDโ the real group id of the shell at startup.KSHUIDโ the real user id of the shell at startup.KSH_MATCHโ the last string that matched, bestie ๐ . In a future version this is gonna be an indexed array with indexes 1 and up capturing matching groups (iykyk). It gets set by string comparisons (=and!=) in double-bracket test expressions when a match is found (so, when!=returns false), bycasewhen a match is encountered, and by all of these substitution ops:${x#pat},${x##pat},${x%pat},${x%%pat},${x/pat/rpl},${x/#pat/rpl},${x/%pat/rpl},${x//pat/rpl}and${x@/pat/rpl}. Want an example? Go peek at the end of the Emacs editing mode docs โจ.KSH_VERSIONโ the shell's name (its self-identification) and version. Read-only, no touching ๐. Also peep the version commands in the โEmacs editing modeโ and โVi editing modeโ sections down below.LINENOโ the line number of the function or shell script that's running right now ๐.LINESโ set to the number of lines in your terminal or window. Defaults to 24, and it's always set โ unless it got imported or unset. SeeCOLUMNS.OLDPWDโ the previous working directory. It's unset ifcdhasn't successfully changed directories since the shell started, or if the shell literally doesn't know where it is ๐ซ .OPTARGโ when you're usinggetopts, this holds the argument for a parsed option, if that option needs one.OPTINDโ the index of the next argument to be processed when usinggetopts. Assign1to it andgetoptswill start over from the beginning of the arguments next time it's invoked ๐.PATHโ a colon-separated list of directories (semicolon on OS/2) that get searched when the shell looks for commands and for files sourced with the โ.โ command (see below). An empty string coming from a leading or trailing (semi)colon, or from two adjacent ones, counts as a โ.โ โ aka the current directory ๐.PATHSEPโ a colon (semicolon on OS/2), purely for the user's convenience ๐.PGRPโ the process ID of the shell's process group leader.PIPESTATUSโ an array holding the errorlevel (exit status) codes, one by one, of the last pipeline that ran in the foreground ๐.PPIDโ the process ID of the shell's parent.PS1โ the primary prompt for interactive shells. Parameter, command and arithmetic substitutions all happen in it, and!gets replaced with the current command number (see thefccommand below). Want a literal!in your prompt? Just put โ!!โ inPS1๐.
The default prompt is โ$ โ for non-root users and โ# โ for root. And lowkey important: if mksh is invoked by root and PS1 does not contain a # character, the default value will be used even if PS1 already exists in the environment ๐
The mksh distribution ships with a sample dot.mkshrc containing a sophisticated example, but you might vibe with this one instead (heads up: ${HOSTNAME:=$(hostname)} and the root-vs-user distinguishing clause are, in this example, executed at PS1 assignment time, while $USER and $PWD are escaped and therefore get evaluated every single time a prompt is displayed ๐):
PS1='${USER:=$(id -un)}'"@${HOSTNAME:=$(hostname)}:\$PWD $(
if (( USER_ID )); then print \$; else print \#; fi) "
Also note that since the command-line editors try to figure out how long the prompt is (so they know how far it is to the edge of the screen ๐), escape codes in your prompt tend to mess everything up. You can tell the shell not to count certain sequences (like escape codes) by prefixing your prompt with a character (like Ctrl+A) followed by a carriage return, and then delimiting the escape codes with that character. Any occurrences of that character in the prompt just aren't printed. And look, don't blame me for this hack โ it's derived from the original ksh88(1), which did print the delimiter character, so you were out of luck if you didn't have any non-printing characters ๐.
Since backslashes and other special characters may be interpreted by the shell, to set PS1 you either escape the backslash itself or use double quotes. The double-quote route is more practical, fr. Here's a more complex example that avoids directly entering special characters (for example with ^V in the emacs editing mode), and embeds the current working directory โ in reverse video (colour would work too) โ into the prompt string โจ:
x=$(print \\001) # otherwise unused char
PS1="$x$(print \\r)$x$(tput so)$x\$PWD$x$(tput se)$x> "
Due to a strong suggestion from David G. Korn, mksh now also supports this form ๐:
PS1=$'\1\r\1\e[7m\1$PWD\1\e[0m\1> '
PS2โ the secondary prompt string, by default โ>โ, used when more input is needed to complete a command.PS3โ the prompt used by theselectstatement when reading a menu selection. Default is โ#?โ.PS4โ used to prefix commands that get printed during execution tracing (see theset -xcommand below). Parameter, command and arithmetic substitutions are performed before it's printed. Default is โ+โ. You might wanna set it to โ[$EPOCHREALTIME]โ instead, to get timestamps โฐ.PWDโ the current working directory. May be unset or empty if the shell doesn't know where it is ๐ซฅ.RANDOMโ every single timeRANDOMis referenced, it first gets assigned a number between 0 and 32767 from a Linear Congruential PRNG ๐ฒ.REPLYโ the default parameter for thereadcommand when you don't give any names. It's also used inselectloops to store the value read from standard input.SECONDSโ the number of seconds since the shell started. Or, if the parameter has been assigned an integer value, the number of seconds since that assignment plus the value that got assigned โฑ๏ธ.TMOUTโ if you set it to a positive integer in an interactive shell, it specifies the maximum number of seconds the shell will wait for input after printing the primary prompt (PS1). Exceed that time and the shell exits ๐ช๐จ.TMPDIRโ the directory where temporary shell files get created. If this parameter isn't set, or doesn't contain the absolute path of a writable directory, temp files get created in/tmp.USER_IDโ the effective user id of the shell at startup.
๐ธ Tilde expansion ๐ธ
Tilde expansion runs in parallel with parameter substitution, and it applies to words starting with an unquoted ~. In parameter assignments (like the ones preceding a simple-command, or the ones appearing in the arguments of a declaration utility), tilde expansion happens after any assignment โ i.e. after the equals sign โ or after an unquoted colon (:); login names are delimited by colons too. The Korn shell, except in POSIX mode, always expands tildes after unquoted equals signs, not just in assignment context (see below), and enables tab completion for tildes after all unquoted colons during command line editing โจ๏ธโจ.
The characters following the tilde, up to the first / if there is one, are assumed to be a login name. If that login name is empty, + or -, the simplified value of the HOME, PWD or OLDPWD parameter is substituted, respectively. Otherwise the password file gets searched for the login name, and the tilde expression is substituted with that user's home directory. If the login name isn't found in the password file, or if any quoting or parameter substitution happens inside the login name, no substitution is performed ๐
.
The home directories of previously expanded login names get cached and reused. The alias -d command can list, change and add to this cache (e.g. alias -d fac=/usr/local/facilities; cd ~fac/bin). Obsessed with a good cache ๐พ.
๐ฆ Brace expansion (alternation) ๐ฆ
Brace expressions look like this:
prefix{str1,...,strN}suffix
The expressions expand to N words, each one being the concatenation of prefix, stri and suffix (e.g. โa{c,b{X,Y},d}eโ expands to four words: โaceโ, โabXeโ, โabYeโ and โadeโ). As that example shows, brace expressions can be nested, and the resulting words are not sorted ๐ช๏ธ. Brace expressions must contain an unquoted comma (,) for expansion to occur (so {} and {foo} are not expanded, sorry bestie). Brace expansion happens after parameter substitution and before file name generation.
๐ File name patterns ๐
A file name pattern is a word containing one or more unquoted ?, *, +, @ or ! characters, or [...] sequences. Once brace expansion has been done, the shell replaces file name patterns with the sorted names of all the files matching the pattern (and if no files match, the word is left unchanged, no cap). The pattern elements mean this:
?โ matches any single character.*โ matches any sequence of octets.[...]โ matches any of the octets inside the brackets. Ranges of octets can be specified by separating two octets with a-(e.g. โ[a0-9]โ matches the letteraor any digit). Character classes can be specified by wrapping the class name between[:and:](e.g. โ[[:alpha:][:digit:].]โ matches any ASCII letter or digit and the full stop) ๐.
To represent itself, a - must either be quoted or be the first or last octet in the octet list. Same energy for ]: if it's meant to represent itself instead of the end of the list, it must be quoted or be the first octet in the list. Also, a ! appearing at the start of the list has special meaning (see below), so to represent itself it must be quoted or appear later in the list. And a ^ at the beginning of the list must be quoted or appear later. Got it? Got it ๐.
[!...]โ just like[...], except it matches any octet not inside the brackets.*(pattern|...|pattern)โ matches any string of octets that matches zero or more occurrences of the specified patterns. Example: the pattern*(foo|bar)matches the strings โโ, โfooโ, โbarโ, โfoobarfooโ, etc. ๐ฏ+(pattern|...|pattern)โ matches any string of octets that matches one or more occurrences of the patterns you listed. Example:+(foo|bar)matchesfoo,bar,foobar, etc. it's giving "one or more, bestie" โจ?(pattern|...|pattern)โ matches the empty string, or a string that matches one of the patterns. Example:?(foo|bar)only matches"",fooandbar. yes the empty string is invited too ๐@(pattern|...|pattern)โ matches a string that matches exactly one of the patterns. Example:@(foo|bar)only matchesfooandbar. pick one, queen ๐!(pattern|...|pattern)โ matches any string that does not match one of the patterns. Examples:!(foo|bar)matches every string exceptfooandbar;!(*)matches no strings at all;!()*matches all strings (think about it ๐ง ). the villain arc of globbing i fear ๐
The following character classes are supported (note all POSIX references assume the C locale; EBCDIC systems use the bytes from the codepage that map to the named ASCII characters so e.g. [[:upper:]] is correct while [A-Z] will contain probably-unwanted characters on EBCDIC systems):
<โ (BSD) the null string at the beginning of a word>โ (BSD) the null string at the end of a wordalnumโ (POSIX) alphanumerical (alpha or digit)alphaโ (POSIX) alphabetical (upper or lower)asciiโ (GNU bash) any 7-bit ASCII character except NULblankโ (POSIX) space or horizontal tabcntrlโ (POSIX) ASCII C0 control characters (\x00โ\x1F) or\x7Fdigitโ (POSIX) ASCII decimal digits (0โ9)graphโ (POSIX) alnum or punct (!โ~)lowerโ (POSIX) ASCII lowercase letters (aโz)printโ (POSIX) space or graph (\x20โ~)punctโ (POSIX) punctuation (graph except alnum):
!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~
sh_aliasโ (mksh) valid in alias names: alnum or!%+,-.:@[]_sh_edqโ (mksh) quoted by tab completion:
"#$&'()*:;<=>?[\\`{|}~
sh_ifsโ (mksh) IFS whitespace, IFS non-whitespace, NUL (via$IFS)sh_ifswsโ (mksh) IFS WS candidates: space, horizontal tab, linefeedsh_nlโ (mksh) linefeed or (OS/2 TEXTMODE only) carriage returnsh_quoteโ (mksh) characters requiring quoting, minus space:
\x09\x0A"#$&'()*;<=>?[\\]`{|}~
spaceโ (POSIX) horizontal tab, line feed, vertical tab, form feed, carriage return, space (\x09โ\x0D\x20)upperโ (POSIX) ASCII uppercase letters (AโZ)wordโ (GNU bash) alphanumerical (alnum) or underscore (_)xdigitโ (POSIX) hexadecimal digits (0โ9AโFaโf) a.k.a. nybbles
Note that complicated globbing, especially with alternatives, is slow; using separate comparisons may (or may not) be faster. no cap, sometimes the simple way just eats ๐ฅ
Note that mksh (and pdksh) never matches . and .., but AT&T UNIX ksh, Bourne sh and GNU bash do. different strokes bestie ๐
Note that none of the above pattern elements match either a period (.) at the start of a file name or a slash (/), even if they are explicitly used in a [...] sequence; also, the names . and .. are never matched, even by the pattern .*. them's just not invited, periodt ๐
If the markdirs option is set, any directories that result from file name generation are marked with a trailing /.
๐ธ Input/output redirection ๐ธ
When a command is executed, its standard input, standard output and standard error (file descriptors 0, 1 and 2, respectively) are normally inherited from the shell. Three exceptions to this are commands in pipelines, for which standard input and/or standard output are those set up by the pipeline, asynchronous commands created when job control is disabled, for which standard input is initially set to /dev/null, and commands for which any of the following redirections have been specified:
>fileโ standard output is redirected to file. If file does not exist, it is created; if it does exist, is a regular file, and thenoclobberoption is set, an error occurs; otherwise, the file is truncated. Note that this means the commandcmd <foo >foowill openfoofor reading and then truncate it when it opens it for writing, beforecmdgets a chance to actually readfoo. sabotage, honestly ๐ญ>|fileโ same as>, except the file is truncated, even if thenoclobberoption is set. it does not care, it will clobber ๐>>fileโ same as>, except if file exists it is appended to instead of being truncated. Also, the file is opened in append mode, so writes always go to the end of the file (seeopen(2)). cozy little addition at the end โจ<fileโ standard input is redirected from file, which is opened for reading.<>fileโ same as<, except the file is opened for reading and writing.<<markerโ after reading the command line containing this kind of redirection (called a "here document"), the shell copies lines from the command source into a temporary file until a line matching marker is read. When the command is executed, standard input is redirected from the temporary file. If marker contains no quoted characters, the contents of the temporary file are processed as if enclosed in double quotes each time the command is executed, so parameter, command and arithmetic substitutions are performed, along with backslash (\) escapes for$,`,\and\newline, but not for". If multiple here documents are used on the same command line, they are saved in order. ๐
If no marker is given, the here document ends at the next << and substitution will be performed. If marker is only a set of either single '' or double "" quotes with nothing in between, the here document ends at the next empty line and substitution will not be performed. sneaky little rules, iykyk
<<-markerโ same as<<, except leading tabs are stripped from lines in the here document.<<<wordโ same as<<, except that word is the here document. This is called a here string. cute one-liner energy fr fr ๐<&fdโ standard input is duplicated from file descriptor fd. fd can be a single digit, indicating the number of an existing file descriptor; the letterp, indicating the file descriptor associated with the output of the current co-process; or the character-, indicating standard input is to be closed.>&fdโ same as<&, except the operation is done on standard output.&>fileโ same as>file 2>&1. This is a deprecated (legacy) GNU bash extension supported by mksh which also supports the preceding explicit fd digit, for example,3&>fileis the same as3>file 2>&3in mksh but a syntax error in GNU bash. legacy behavior bestie, it's giving elder energy&>|file,&>>file,&>&fdโ same as>|file,>>fileor>&fd, followed by2>&1, as above. These are mksh extensions. โจ
In any of the above redirections, the file descriptor that is redirected (i.e. standard input or standard output) can be explicitly given by preceding the redirection with a single digit. Parameter, command and arithmetic substitutions, tilde substitutions, and, if the shell is interactive, file name generation are all performed on the file, marker and fd arguments of redirections. Note, however, that the results of any file name generation are only used if a single file is matched; if multiple files match, the word with the expanded file name generation characters is used. Note that in restricted shells, redirections which can create files cannot be used. ๐ซ
For simple-commands, redirections may appear anywhere in the command; for compound-commands (if statements, etc.), any redirections must appear at the end. Redirections are processed after pipelines are created and in the order they are given, so the following will print an error with a line number prepended to it:
$ cat /foo/bar 2>&1 >/dev/null | pr -n -t
File descriptors created by I/O redirections are private to the shell. ๐คซ
๐งฎ Arithmetic expressions ๐งฎ
Integer arithmetic expressions can be used with the let command, inside $((...)) expressions, inside array references (e.g. name[expr]), as numeric arguments to the test command, and as the value of an assignment to an integer parameter.
โ ๏ธ Warning: This also affects implicit conversion to integer, for example as done by the let command. Never use unchecked user input, e.g. from the environment (although the shell tracks import status and refuses to automatically coerce those), in arithmetic context! this is the part where you don't get sloppy ๐ญ
Expressions are calculated using signed arithmetic and the mksh_ari_t type (a 32-bit signed integer), unless they begin with a sole # character, in which case they use mksh_uari_t (a 32-bit unsigned integer).
Expressions may contain alpha-numeric parameter identifiers, array references and integer constants and may be combined with the following C operators (listed and grouped in increasing order of precedence):
Unary operators:
+ - ! ~ ++ --
Binary operators:
,
= += -= *= /= %= <<= >>= ^<= ^>= &= ^= |=
||
&&
|
^
&
== !=
< <= > >=
<< >> ^< ^>
+ -
* / %
Ternary operators:
?: (precedence is immediately higher than assignment)
Grouping operators:
( )
Integer constants and expressions are calculated using an exactly 32-bit wide, signed (two's complement) or unsigned, type with silent wraparound on integer overflow. Integer constants may be specified with arbitrary bases using the notation base#number, where base is a decimal integer specifying the base (up to 36), and number is a number in the specified base. Additionally, base-16 integers may be specified by prefixing with 0x (case-insensitive) in all forms of arithmetic expressions, except as numeric arguments to the test built-in utility. Prefixing numbers with a sole digit zero (0) does not cause interpretation as octal (except in POSIX mode, as required by the standard), as that's unsafe. Prefixing with 10# forces interpretation as decimal, even with leading zeros. An unset or empty parameter evaluates to 0 in integer context. maths but make it fashion ๐
okay so, numbers with base one?? Yes bestie, that's a real mksh thing, it's a special little mksh extension ๐
. It treats them as either (8-bit transparent) ASCII or Universal Coded Character Set codepoints, and which one you get depends on the shell's [utf8-mode flag] (current setting), obviously. The AT&T UNIX ksh93 syntax of 'x' instead of 1#x is also supported โ legacy icons stay winning โจ.
important though!!! NUL bytes (integral value of zero) cannot be used. Periodt. And ifxisn't comprised of exactly one valid character, the behaviour is undefined (usually, the shell aborts with a parse error, but rarely, it succeeds, e.g. on the sequenceC2 20). So if you're a user of this feature (as opposed toread -a), you must validate the input first. Check โCAVEATSโ for UTF-8 mode handling, bestie. Also base-1 integers don't work well with a number of other shell features, such as reentry-safe output; useprint -Aorread -aif possible. ๐
โจ the operators, explained โจ
The vibes here are simple: the operators are evaluated as follows:
- unary
+โ Result is the argument (included for completeness). It's giving "we did this for symmetry" ๐ - unary
-โ Negation. !โ Logical NOT; the result is1if argument is zero,0if not.~โ Arithmetic (bit-wise) NOT.++โ Increment; must be applied to a parameter (not a literal or other expression). The parameter is incremented by1. When used as a prefix operator, the result is the incremented value of the parameter; when used as a postfix operator, the result is the original value of the parameter.--โ Similar to++, except the parameter is decremented by1.,โ Separates two arithmetic expressions; the left-hand side is evaluated first, then the right. The result is the value of the expression on the right-hand side.=โ Assignment; the variable on the left is set to the value on the right.+=-=*=/=%=<<=>>=^<=^>=&=^=|=โ Assignment operators.<var><op>=<expr>is the same as<var>=<var><op><expr>, with any operator precedence in<expr>preserved. For example,var1 *= 5 + 3is the same as specifyingvar1 = var1 * (5 + 3). ๐งฎ||โ Logical OR; the result is1if either argument is non-zero,0if not. The right argument is evaluated only if the left argument is zero.&&โ Logical AND; the result is1if both arguments are non-zero,0if not. The right argument is evaluated only if the left argument is non-zero.|โ Arithmetic (bit-wise) OR.^โ Arithmetic (bit-wise) XOR (exclusive-OR).&โ Arithmetic (bit-wise) AND.==โ Equal; the result is1if both arguments are equal,0if not.!=โ Not equal; the result is0if both arguments are equal,1if not.<โ Less than; the result is1if the left argument is less than the right,0if not.<=>>=โ Less than or equal, greater than, greater than or equal. See<.<<>>โ Shift left (right); the result is the left argument with its bits arithmetically (signed operation) or logically (unsigned expression) shifted left (right) by the amount given in the right argument.^<^>โ Rotate left (right); the result is similar to shift, except that the bits shifted out at one end are shifted in at the other end, instead of zero or sign bits. ๐+-*/โ Addition, subtraction, multiplication and division.%โ Remainder; the result is the symmetric remainder of the division of the left argument by the right. To get the mathematical modulus ofa mod b, use the formula(a % b + b) % b.<arg1>?<arg2>:<arg3>โ If<arg1>is non-zero, the result is<arg2>; otherwise the result is<arg3>. The non-result argument is not evaluated.
๐ฆ Co-processes ๐ฆ
A co-process (which is a pipeline created with the |& operator) is an asynchronous process that the shell can both write to (using print -p) and read from (using read -p). The input and output of the co-process can also be manipulated using >&p and <&p redirections, respectively. Once a co-process has been started, another can't be started until the co-process exits, or until the co-process's input has been redirected using an exec n>&p redirection. If a co-process's input is redirected in this way, the next co-process to be started will share the output with the first co-process, unless the output of the initial co-process has been redirected using an exec n<&p redirection. ๐ฏ
Some notes concerning co-processes:
- The only way to close the co-process's input (so the co-process reads an end-of-file) is to redirect the input to a numbered file descriptor and then close that file descriptor:
exec 3>&p; exec 3>&-
- In order for co-processes to share a common output, the shell must keep the write portion of the output pipe open. This means that end-of-file will not be detected until all co-processes sharing the co-process's output have exited (when they all exit, the shell closes its copy of the pipe). This can be avoided by redirecting the output to a numbered file descriptor (as this also causes the shell to close its copy). Note that this behaviour is slightly different from the original Korn shell which closes its copy of the write portion of the co-process output when the most recently started co-process (instead of when all sharing co-processes) exits. ๐ญ
print -pwill ignoreSIGPIPEsignals during writes if the signal is not being trapped or ignored; the same is true if the co-process input has been duplicated to another file descriptor andprint -unis used.
๐ Functions ๐
Functions are defined using either Korn shell function function-name syntax or the Bourne/POSIX shell function-name() syntax (see below for the difference between the two forms). Functions are like .-scripts (i.e. scripts sourced using the . built-in) in that they are executed in the current environment. However, unlike .-scripts, shell arguments (i.e. positional parameters $1, $2, etc.) are never visible inside them. When the shell is determining the location of a command, functions are searched after special built-in commands, before builtins and the PATH is searched. ๐
An existing function may be deleted using unset -f function-name. A list of functions can be obtained using typeset +f and the function definitions can be listed using typeset -f. The autoload command (which is an alias for typeset -fu) may be used to create undefined functions: when an undefined function is executed, the shell searches the path specified in the FPATH parameter for a file with the same name as the function which, if found, is read and executed. If after executing the file the named function is found to be defined, the function is executed; otherwise, the normal command search is continued (i.e. the shell searches the regular built-in command table and PATH). Note that if a command is not found using PATH, an attempt is made to autoload a function using FPATH (this is an undocumented feature of the original Korn shell). ๐คซ
Functions can have two attributes, โtraceโ and โexportโ, which can be set with typeset -ft and typeset -fx, respectively. When a traced function is executed, the shell's xtrace option is turned on for the function's duration. The โexportโ attribute of functions is currently not used.
Since functions are executed in the current shell environment, parameter assignments made inside functions are visible after the function completes. If this is not the desired effect, the typeset command can be used inside a function to create a local parameter. Note that AT&T UNIX ksh93 uses static scoping (one global scope, one local scope per function) and allows local variables only on Korn style functions, whereas mksh uses dynamic scoping (nested scopes of varying locality). Note that special parameters (e.g. $$, $!) can't be scoped in this way.
The exit status of a function is that of the last command executed in the function. A function can be made to finish immediately using the return command; this may also be used to explicitly specify the exit status. Note that when called in a subshell, return will only exit that subshell and will not cause the original shell to exit a running function (see the while...read loop FAQ). ๐
Functions defined with the function reserved word are treated differently in the following ways from functions defined with the () notation:
- The
$0parameter is set to the name of the function (Bourne-style functions leave$0untouched). OPTINDis saved/reset and restored on entry and exit from the function sogetoptscan be used properly both inside and outside the function (Bourne-style functions leaveOPTINDuntouched, so usinggetoptsinside a function interferes with usinggetoptsoutside the function).- Shell options (
set -o) except-p(-o privileged) have local scope, i.e. changes inside a function are reset upon its exit. โจ
In the future, the following differences may also be added:
- A separate trap/signal environment will be used during the execution of functions. This will mean that traps set inside a function will not affect the shell's traps and signals that are not ignored in the shell (but may be trapped) will have their default effect in a function.
- The
EXITtrap, if set in a function, will be executed after the function returns.
๐ Command execution ๐
After evaluation of command-line arguments, redirections and parameter assignments, the type of command is determined: a special built-in command, a function, a normal builtin or the name of a file to execute found using the PATH parameter. The checks are made in the above order. Special built-in commands differ from other commands in that the PATH parameter is not used to find them, an error during their execution can cause a non-interactive shell to exit, and parameter assignments that are specified before the command are kept after the command completes. Regular built-in commands are different only in that the PATH parameter is not used to find them. ๐
POSIX special built-in utilities:
., :, break, continue, eval, exec, exit, export, readonly, return, set,
shift, times, trap, unset
Additional mksh commands keeping assignments:
source, typeset
All other builtins are not special; these are at least:
[, alias, bg, bind, builtin, cd, command, echo, false, fc, fg, getopts, jobs, kill, let, print, pwd, read, realpath, rename, suspend, test, true, ulimit, umask, unalias, wait, whence
okay so the moment the shell has figured out exactly what kind of command we're dealing with, any command-line parameter assignments get performed and exported for as long as that command runs. no cap. ๐
Now for the main event โ here's the full rundown of the special and regular built-in commands and the builtin-adjacent reserved words, plus a couple of optional utilities that tagged along. Buckle up, bestie ๐
. *file* [*arg* ...]
(keeps assignments, special) bestie this is THE "dot" command โจ It executes the commands inside file in the current environment โ no subshell, we're staying right here, we're comfortable. The shell goes looking for file in the directories listed in PATH. If arguments are given, the positional parameters can be used to grab them while file is busy running. And if you give it no arguments? Then the positional parameters are just whatever the environment the command was used in already had. ๐
: [...]
(keeps assignments, special) The null command. That's it, that's the whole vibe. It does nothing and the exit status is set to zero. A little icon of emptiness ๐
Lb64decode [string]
(dot.mkshrc function) Decodes string, or standard input, into binary. ๐ง
Lb64encode [string]
(dot.mkshrc function) Encodes string, or standard input, as base64. ๐ฅ
Lbafh_init
Lbafh_add [string]
Lbafh_finish
(dot.mkshrc functions) Okay these three together implement the Better Avalanche for Jenkins Hash (IV=1) ๐ซถ and yes, clever girl, it's the exact same hash mksh currently uses internally. The ritual goes like this: call Lbafh_init first, then call Lbafh_add as many times as you need until all your input is read, then call Lbafh_finish โ which writes the result into the unsigned integer Lbafh_v variable for you to consume. Slay. ๐
Lstripcom [file ...]
(dot.mkshrc function) Literally cat(1) but with a glow-up: it strips out any empty lines and comments (comments being anything from a # character onwards, and no, there are no escapes โ sorry bestie) and squashes any amount of whitespace down to a single space character. Tidy โจ
[ expression ]
(regular) See test. That's the whole note, go look at test. ๐
alias [-d | -t [-r] | -+x] [-p] [+] [name[=value] ...]
(regular) With no arguments, alias lists all the aliases. For any name without a value, the existing alias for it gets listed. And any name with a value defines an alias โ see "Aliases" above for the whole lore.
The characters [][A-Za-z0-9_!%+,.@:-] are all valid in names, with two little caveats: they can't begin with a plus or a hyphen-minus, and [[ is not a valid alias name. Noted. ๐
When you're listing aliases, one of two formats shows up. Normally aliases are listed as name=value, where value is quoted however it needs to be. But if the options were preceded with +, or a lone + is given on the command line, only name gets printed.
-dโ makes it so directory aliases (the ones used in tilde expansion) are listed or set โ see "Tilde expansion" above.-pโ each alias gets listed with the stringaliasprefixed onto it.-tโ says we're listing/setting tracked aliases (any values you give with the command are ignored for tracked aliases, btw).-rโ says all tracked aliases are getting reset.-xโ sets (and+xclears) the export attribute of an alias, or, if you don't give any names, lists the aliases that have the export attribute. (Heads up: exporting an alias has no effect. It just vibes there.)
autoload
(built-in alias) See "Functions" above. ๐ฆ
bg [job ...]
(regular, needs job control) Resumes the stopped job(s) you specify, in the background. No jobs given? %+ is assumed. See "Job control" below for the deets. ๐
bind -l
(regular) Lists the names of the editing commands that strings can be bound to. See "Emacs editing mode" for more. โจ๏ธ
bind [string ...]
Lists the current bindings โ for string if you gave one, otherwise all of them. Note: default prefix bindings (1=Esc, 2=^X, 3=NUL) are assumed. ๐
bind string=[editing-command] [...]
bind -m string=substitute [...]
To string โ which should consist of a control character, optionally preceded by one of the three prefix characters and optionally followed by a tilde โ the editing-command gets bound, so that future input of that string will immediately invoke that editing command. If a tilde postfix is given, a tilde trailing the control character is ignored. And if -m (macro) is given, future input of string gets replaced by the given NUL-terminated substitute string, wherein prefix/control/tilde characters that are mapped to editing commands (but not those mapped to other macros) will be processed. ๐ตโ๐ซ
The entire argument can also be written using extended caret notation: ^Z represents Ctrl-Z; ^+Z represents UTF-8 Meta-Ctrl-Z; and both ^!Z and \x9A represent ASCII Meta-Ctrl-Z. Otherwise, a backslash escapes the next character, which removes the special meaning from backslashes, carets and (for the string part) equals signs. (Those backslashes obviously have to be quoted for the shell, bestie.) And note: even though only three prefix characters โ usually Esc, ^X and NUL โ are usable, some multi-character sequences can still be supported. ๐
break [level]
(keeps assignments, special) Exits out of the levelth inner-most for, select, until or while loop. level defaults to 1. Escape the loop, periodt. ๐ช
builtin [--] command [arg ...]
(regular) Executes the built-in command command. Simple as that. โจ
\builtin command [arg ...]
(regular, decl-forwarder) Same as builtin. But additionally it acts as a declaration utility forwarder โ meaning it counts as a declaration utility (see "Tilde expansion") if and only if command is a declaration utility. Sneaky but iconic. ๐ซถ
cd [-L] [dir]
cd -P [-e] [dir]
chdir [-eLP] [dir]
cd [-L] [dir]
cd -P [-e] [dir]
chdir [-eLP] [dir]
(regular) Sets the working directory to dir. If CDPATH is set, it hands you the search path for the directory containing dir; an unset or empty path means the current directory. If dir is found in some component of the CDPATH search path that isn't an unset or empty path, the name of the new working directory gets written to standard output. If dir is missing, the home directory HOME is used. And if dir is -? Then the previous working directory is used (see the OLDPWD parameter). ๐
Use the -L option (logical path), or leave the physical option unset (see the set command below), and references to .. in dir are relative to the path you took to get to the directory. Use -P (physical path), or have the physical option set, and .. is relative to the filesystem directory tree instead. The PWD and OLDPWD parameters get updated to reflect the current and old working directory respectively. And if -e is set for physical filesystem traversal and PWD couldn't be set, the exit code is 1; greater than 1 if an error occurred, 0 otherwise. ๐
cd [-eLP] old new
chdir [-eLP] old new
(regular) Swaps the string new in for old in the current directory, and then the shell tries to change to that brand-new directory. Glow-up complete โจ
cls
(dot.mkshrc alias) Reinitialise the display (a hard reset). ๐งผ
command [-pVv] cmd [arg ...]
(regular, decl-forwarder) If neither -v nor -V is given, cmd is executed exactly as if command hadn't been specified at all โ with two little exceptions. First: cmd can't be a shell function. Second: special built-in commands lose their specialness, i.e. redirection and utility errors do not cause the shell to exit, and command assignments are not permanent. ๐
-pโ a default search path is used instead of the currentPATH; the actual value of that path is system-dependent.-vโ instead of executing cmd, info about what would be executed is given for each argument. For builtins, functions and keywords, their names are simply printed; for aliases, a command that defines them is printed; for utilities found by searching thePATHparameter, the full path of the command is printed. If no command is found (i.e. the path search fails), nothing is printed andcommandexits with a non-zero status.-Vโ like-v, but more verbose. Extra chatty. ๐ฌ
continue [level]
(keeps assignments, special) Jumps right back to the beginning of the levelth inner-most for, select, until or while loop. level defaults to 1. Round two, bestie ๐
dirs [-lnv]
(dot.mkshrc function) Prints the directory stack. ๐๏ธ
-lโ makes tilde expansion occur in the output.-nโ makes it wrap lines before 80 columns.-vโ makes it a numbered vertical output.
doch
(dot.mkshrc alias) Executes the last command with sudo(8). ๐
echo [-Een] [arg ...]
(regular) Warning: this utility is not portable โ use the standard Korn shell built-in utility print in new code instead. ๐
โโ๏ธ
It prints the arguments to standard output, separated by spaces and followed by a newline. That newline gets suppressed if any of the arguments contain the backslash sequence \c. See the print command below for a list of the other backslash sequences that get recognised.
The options exist purely for compatibility with BSD shell scripts. -E suppresses backslash interpretation, -e enables it (that's normally the default), -n suppresses the trailing newline, and anything else causes the word to be printed as an argument instead.
If the posix or sh option is set, or this is a direct builtin call, or print -R, then only the first argument is treated as an option โ and only if it is exactly -n. Backslash interpretation is disabled. ๐
enable [-anps] [name ...]
(dot.mkshrc function) Hides and unhides built-in utilities, aliases and functions, plus the ones defined in dot.mkshrc. ๐
- No name, or
-pโ builtins get printed (behind the stringenable, followed by-nif the builtin is currently disabled). Otherwise they get disabled (if-nis given) or re-enabled. -aโ prints all builtins, not just the enabled ones. (When printing, only enabled builtins show up by default.)-nโ prints only the disabled builtins instead.-sโ limits the list to POSIX special builtins.
eval command ...
(keeps assignments, special) The arguments all get concatenated together, with a space between each one, forming a single string โ which the shell then parses and executes in the current execution environment. Chaotic, powerful, iconic. ๐ช
exec (keeps assignments, special) ๐
exec [-a argv0] [-c] [command [arg ...]]
okay so bestie, this one is intense. The command (with its args) gets executed without forking, fully replacing the shell process. Like, the shell literally becomes the command. This is absolute โ exec never returns, even if the command is not found. Not "usually doesn't return". Never. ๐
The -a option lets you set a different argv[0] value, and -c clears the environment before executing the child process, except for the _ parameter and direct assignments.
In โPOSIX modeโ, a failed exec does return to an interactive shell prompt. But heads up โ the execution environment may still contain traces of the attempt to pass control and is not fully restored. So it's giving "we tried our best" energy. ๐ญ
If no command is given except for I/O redirection, the I/O redirection is permanent and the shell is not replaced. Any file descriptors greater than 2 which are opened or dup(2)'d in this way are not made available to other executed commands (i.e. commands that are not built-in to the shell). Note that the Bourne shell differs here; it does pass these file descriptors on.
exit (keeps assignments, special) ๐ช
exit [status]
The shell or subshell exits with the specified errorlevel (or the current value of the $? parameter).
export (keeps assignments, special, decl-util) ๐
export [-p] [parameter[=value]]
Sets the export attribute of the named parameters. Exported parameters are passed in the environment to executed commands. If values are specified, the named parameters are also assigned. This is a declaration utility.
If no parameters are specified, all parameters with the export attribute set are printed one per line: either their names, or, if a โ-โ with no option letter is specified, name=value pairs, or, with the -p option, export commands suitable for re-entry. Iconic behaviour honestly. โจ
extproc (OS/2)
Null command required for shebang-like functionality. That's it. That's the whole job. ๐ซถ
false (regular)
A command that exits with a non-zero status. Yes she's simple. Yes she's essential. ๐
fc (regular) ๐
fc [-e editor | -l [-n]] [-r] [first [last]]
first and last select commands from the history. Commands can be selected by history number (negative numbers go backwards from the current, most recent, line) or a string specifying the most recent command starting with that string. The -l option lists the command on standard output, and -n inhibits the default command numbers. The -r option reverses the order of the list. Without -l, the selected commands are edited by the editor specified with the -e option or, if no -e is specified, the editor specified by the FCEDIT parameter (if this parameter is not set, /bin/ed is used), and the result is executed by the shell.
fc (the other form)
fc -e - | -s [-g] [old=new] [prefix]
Re-execute the selected command (the previous command by default) after performing the optional substitution of old with new. If -g is specified, all occurrences of old are replaced with new. The meaning of -e - and -s is identical: re-execute the selected command without invoking an editor. This command is usually accessed with the predefined:
alias r='fc -e -'
fg (regular, needs job control) ๐ฅ
fg [job ...]
Resume the specified job(s) in the foreground. If no jobs are specified, %+ is assumed. See โJob controlโ below for more information.
functions (built-in alias)
functions [name ...]
Display the function definition commands corresponding to the listed, or all defined, functions.
getopts (regular) ๐ง
getopts optstring name [arg ...]
Used by shell procedures to parse the specified arguments (or positional parameters, if no arguments are given) and to check for legal options. Options that do not take arguments may be grouped in a single argument. If an option takes an argument and the option character is not the last character of the word it is found in, the remainder of the word is taken to be the option's argument; otherwise, the next word is the option's argument.
optstring contains the option letters to be recognised. If a letter is followed by a colon, the option takes an argument.
Each time getopts is invoked, it places the next option in the shell parameter name. If the option was introduced with a โ+โ, the character placed in name is prefixed with a โ+โ. If the option takes an argument, it is placed in the shell parameter OPTARG.
When an illegal option or a missing option argument is encountered, a question mark or a colon is placed in name (indicating an illegal option or missing argument, respectively) and OPTARG is set to the option letter that caused the problem. Furthermore, unless optstring begins with a colon, a question mark is placed in name, OPTARG is unset and a diagnostic is shown on standard error.
getopts records the index of the argument to be processed by the next call in OPTIND. When the end of the options is encountered, getopts returns a non-zero exit status. Options end at the first argument that does not start with a โ-โ (non-option argument) or when a โ--โ argument is encountered.
Option parsing can be reset by setting OPTIND to 1 (this is done automatically whenever the shell or a shell procedure is invoked).
โ ๏ธ Warning: Changing the value of the shell parameterOPTINDto a value other than1or parsing different sets of arguments without resettingOPTINDmay lead to unexpected results. Like, chaos. Not the cute kind. ๐
hash (built-in alias)
hash [-r] [name ...]
Without arguments, any hashed executable command paths are listed. The -r option causes all hashed commands to be removed from the cache. Each name is searched as if it were a command name and added to the cache if it is an executable command.
hd (dot.mkshrc alias or function) ๐ฆ
hd [file ...]
Hexdump stdin or arguments legibly.
history (built-in alias)
history [-nr] [first [last]]
Same as fc -l (see above).
integer (built-in alias)
integer [flags] [name[=value] ...]
Same as typeset -i (see below).
jobs (regular) ๐
jobs [-lnp] [job ...]
Display information about the specified job(s); if no jobs are specified, all jobs are displayed.
-nโ causes information to be displayed only for jobs that have changed state since the last notification.-lโ if used, the process ID of each process in a job is also listed.-pโ causes only the process group of each job to be printed.
See โJob controlโ below for the format of job and the displayed job.
kill (regular) ๐ช
kill [-s signame | -signum | -signame] { job | pid | pgrp } ...
Send the specified signal to the specified jobs, process IDs or process groups. If no signal is specified, the TERM signal is sent. If a job is specified, the signal is sent to the job's process group. See โJob controlโ below for the format of job.
kill -l (regular)
kill -l [exit-status ...]
Print the signal name corresponding to exit-status. If no arguments are specified, a list of all the signals with their numbers and a short description of each are printed.
let (regular) ๐
let [expression ...]
Each expression is evaluated (see โArithmetic expressionsโ above). If all expressions evaluate successfully, the exit status is 0 (1) if the last expression evaluated to non-zero (zero). If an error occurs during the parsing or evaluation of an expression, the exit status is greater than 1.
Since expressions may need to be quoted, (( expr )) is syntactic sugar for:
{ \\builtin let 'expr'; }
local (built-in alias)
local [flags] [name[=value] ...]
Same as typeset (see below).
mknod (optional) ๐
mknod [-m mode] name b|c major minor
mknod [-m mode] name p
Create a device special file. The file type may be one of b (block type device), c (character type device) or p (named pipe, FIFO). The file created may be modified according to its mode (via the -m option), major (major device number), and minor (minor device number).
This is not normally part of mksh; however, distributors may have added this as builtin as a speed hack.
nameref (built-in alias)
nameref [flags] [name[=value] ...]
Same as typeset -n (see below).
popd (dot.mkshrc function) ๐
popd [-lnv] [+n]
Pops the directory stack and returns to the new top directory. The flags are as in dirs (see above). A numeric argument +n selects the entry in the stack to discard.
print (regular) โจ
print [-AcelNnprsu[n] | -R [-n]] [argument ...]
Print the specified argument(s) on the standard output, separated by spaces, terminated with a newline. The escapes mentioned in โBackslash expansionโ above, as well as โ\cโ, which is equivalent to using the -n option, are interpreted.
The options are as follows:
-Aโ Each argument is arithmetically evaluated; the character corresponding to the resulting value is printed. Empty arguments separate input words. No backslash expansion.-cโ The output is printed columnised, top to bottom then left to right, similar to how tab completion (control character escaping excepted), thekill -lbuilt-in utility, theselectstatement and thers(1)utility do.-eโ Restore backslash expansion after a previous-r.-lโ Change the output word separator to newline.-Nโ Change the output word and line separator to ASCII NUL.-nโ Do not print the trailing line separator.-pโ Print to the co-process (see โCo-processesโ above).-rโ Inhibit backslash expansion.-sโ Print to the history file instead of standard output.-u[n]โ Print to the file descriptorn(defaults to1if omitted) instead of standard output.
The -R option mostly emulates the BSD echo(1) command which does not expand backslashes and interprets its first argument as option only if it is exactly โ-nโ (to suppress the trailing newline). ๐ธ
printf ๐ธ
printf format [arguments ...]
(optional, defer always) If it got compiled in, this one formats and prints the arguments, supporting the bare POSIX-mandated minimum and not a crumb more. And here's the tea: if an external utility of the same name is found, it gets deferred to โ unless you run it as a direct builtin call or from the builtin utility. ๐
pushd ๐
pushd [-lnv]
(dot.mkshrc function) Rotates the top two elements of the directory stack. The options are literally the same as for dirs (see above, bestie), and after acting, pushd changes to the topmost directory stack entry.
pushd [-lnv] +n
(dot.mkshrc function) Rotates the element number n all the way to the top. main character energy honestly โจ
pushd [-lnv] name
(dot.mkshrc function) Pushes name on top of the stack.
pwd ๐
pwd [-LP]
(regular) Prints the present working directory. If you give it no options at all, pwd behaves as if the -P option (print physical path) was used when the physical shell option is set โ and as if -L (print logical path) was used otherwise.
The logical path is the path you used to cd to the current directory. The physical path is determined from the filesystem, by following .. directories to the root directory. No cap. ๐ฆ
r ๐
r [-g] [old=new] [prefix]
(built-in alias) Same as fc -e - (see above). That's it, that's the whole vibe.
read ๐
read [-A | -a] [-d x] [-N z | -n z] [-p | -u[n]] [-t n] [-rs] [p ...]
(regular) Reads a line of input, splits the input into fields using the IFS parameter (see โSubstitutionโ above) or other specified means, and assigns each field to the specified parameters p.
If you specify no parameters, the REPLY parameter catches the result instead. If there are more parameters than fields, the extra parameters get set to the empty string or 0. If there are more fields than parameters, the last parameter gets assigned the remaining fields โ word separators and all. ๐
The options are as follows:
-Aโ Store the result into the parameter p (orREPLY) as an array of words. Only no parameter or one parameter is accepted.-aโ Store the result, without applyingIFSword splitting, into the parameter p (orREPLY) as an array of characters (wide characters if theutf8-modeoption is enacted, octets otherwise). The codepoints are encoded as decimal numbers by default. Only no parameter or one parameter is accepted.-d xโ Use the first byte of x,NULif empty, instead of the ASCII newline character to delimit input lines.-N zโ Instead of reading till end-of-line, read exactly z bytes. Upon EOF, a partial read is returned with exit status1. After a timeout, a partial read is returned with an exit status as ifSIGALRMwere caught.-n zโ Instead of reading till end-of-line, read up to z bytes but return as soon as any bytes are read, e.g. from a slow terminal device, or if EOF or a timeout occurs.-pโ Read from the currently active co-process (see โCo-processesโ above for details) instead of from a file descriptor.-u[n]โ Read from the file descriptor number n (defaults to0, i.e. standard input). โ ๏ธ The argument must immediately follow the option character.-t nโ Interrupt reading after n seconds (specified as a positive decimal value with an optional fractional part). The exit status ofreadis the same as ifSIGALRMwere caught if the timeout occurred, but partial reads may still be returned.-rโ Normally,readstrips backslash-newline sequences and any remaining backslashes from input. This option enables raw mode, in which backslashes are retained and ignored.-sโ The input line is saved to the history. ๐ฐ๏ธ
If the input is a terminal, both the -N and -n options set it into raw mode; they read an entire file if -1 is passed as the z argument.
The first parameter may have a question mark and a string appended to it, in which case the string is used as a prompt (printed to standard error before any input is read) if the input is a tty(4). Like, for example: read nfoo?'number of foos: ' ๐
If no input is read, or a timeout occurred, read exits with a non-zero status. ๐
readonly ๐
readonly [-p] [parameter[=value] ...]
(keeps assignments, special, decl-util) Sets the read-only attribute of the named parameters. If values are given, the parameters are assigned these values before disallowing writes. And once a parameter is made read-only, it cannot be unset and its value cannot be changed. It's locked, periodt. ๐
If you specify no parameters, the names of all parameters with the read-only attribute are printed, one per line โ unless the -p option is used, in which case readonly commands defining all read-only parameters, including their values, are printed.
realpath ๐ค๏ธ
realpath [--] name
(defer with flags) Resolves an absolute pathname corresponding to name. If the resolved pathname either exists or can be created immediately, realpath returns 0 and prints the resolved pathname. Otherwise, or if an error occurs, it issues a diagnostic and returns nonzero.
Oh and heads up: if name ends with a slash (/), resolving to an extant non-directory is also treated as an error. ๐
rename ๐
rename [--] from to
(defer always, needs rename(2)) Renames the file from to to. Both pathnames must be on the same device. This one is intended for emergency situations (like when /bin/mv becomes unusable); it's a thin syscall wrapper, no extras. ๐จ
return โฉ๏ธ
return [status]
(keeps assignments, special) Returns from a function or . script with errorlevel status. If no status is given, the exit status of the last executed command is used. If you use it outside of a function or . script, it has the same effect as exit. ๐
Note:mkshtreats bothprofileandENVfiles as.scripts, while the original Korn shell only treated profiles as.scripts.
rot13 ๐
(dot.mkshrc alias) ROT13-encrypts/-decrypts stdin to stdout. Yes bestie, that's the whole thing. Iconic.
set ๐๏ธ
set [-+abCefhkmnpsUuvXx] [-+o option] [-+A name] [--] [argument ...]
set -- [argument ...]
set -+o
(keeps assignments, special) The set command can be used to show all shell parameters (like typeset -), set (-) or clear (+) shell options, set an array parameter, or set the positional parameters.
Options can be changed using the -+o option syntax, where option is the long name of an option, or using the -+letter syntax, where letter is the option's single letter name (heads up: not all options have both names). Here's the whole table โ short and long names (if extant) plus what each option actually does: โจ
-A nameโ Sets the elements of the array parameter name toargument ...
If -A is used, the array is reset (i.e. emptied) first; if +A is used, the first N elements are set (where N is the number of arguments) and the rest are left untouched. If name ends with a +, the array is appended to instead.
An alternative syntax for the command set -A foo -- a b c; set -A foo+ -- d e โ which is compatible with GNU bash and also supported by AT&T UNIX ksh93 โ is: foo=(a b c); foo+=(d e)
-a|-o allexportโ Make all variables assigned to while enabled as exported.-b|-o notifyโ Print job notification messages asynchronously instead of just before the prompt. Only used with job control (-m).-C|-o noclobberโ Prevent>redirection from overwriting existing files;>|must be used to force overwriting instead.
Note: This is not safe to use for creation of temporary files or lockfiles due to a TOCTOU in a check allowing one to redirect output to/dev/nullor other device files even innoclobbermode. Be careful bestie ๐ญ
-cโ Commands are read from an argument string. Can only be used when the shell is invoked.-e|-o errexitโ Exit (after executing theERRtrap) as soon as an error occurs or a command fails (i.e. exits with a non-zero status). This does not apply to commands whose exit status is explicitly tested by a shell construct such as!,if,untilorwhilestatements. For&&,||and pipelines (but mind-o pipefail), only the status of the last command is tested.-f|-o noglobโ Do not expand file name patterns.-h|-o trackallโ Create tracked aliases for all executed commands (see โAliasesโ above). Enabled by default for non-interactive shells.-i|-o interactiveโ The shell is an interactive shell. This option can only be used when the shell is invoked. See above for details.-k|-o keywordโ Parameter assignments are recognised anywhere in a command.-l|-o loginโ The shell is a login shell. This option can only be used when the shell is invoked. See above for what this means.-m|-o monitorโ Enable job control (default for interactive shells).-n|-o noexecโ Do not execute any commands. Useful for checking the syntax of scripts. Ignored if reading commands from atty.-p|-o privilegedโ The shell is a privileged shell. It is set automatically if, when the shell starts, the real UID or GID does not match the effective UID (EUID) or GID (EGID), respectively. See above for a description of what this means.
If the shell is privileged, setting this flag after startup file processing lets it go full setuid and/or setgid. Clearing the flag makes the shell drop privileges. Changing this flag resets the supplementary groups vector.
-r|-o restrictedโ The shell is a restricted shell. This option can only be used when the shell is invoked. See above for what this means.-s|-o stdinโ If used when the shell is invoked, commands are read from standard input. Set automatically if the shell is invoked with no arguments.
When -s is used with the set command it causes the specified arguments to be sorted ASCIIbetically before assigning them to the positional parameters (or to array name, with -A).
-U,-o utf8-modeโ turns ON UTF-8 support in โEmacs editing modeโ and in the internal string handling functions ๐. This flag is off by default, but you can switch it on right there on the shell command line. It also flips itself on automatically for interactive shells when the POSIX locale uses the UTF-8 codeset, or โ if there's no POSIX locale to speak of โ when theLC_ALL,LC_CTYPEorLANGenvironment variables either case-insensitively equal โUTF-8โ or โutf8โ, or carry that as a codeset modifier. โจ
This build of the shell does baroque locale tracking, meaning set -+U gets changed whenever one of the POSIX locale-related environment variables changes. It's giving watcher energy, honestly. ๐
-u,-o nounsetโ referencing an unset parameter is treated as an error, except for โ$@โ or โ$*โ, and unless one of the โ-โ, โ+โ or โ=โ modifiers is in play. no cap, touching unset vars is a whole crime here ๐ซ-v,-o verboseโ write shell input to standard error as it's read. she's narrating her own life ๐-X,-o markdirsโ mark directories with a trailing โ/โ during globbing โจ-x,-o xtraceโ print commands when they're executed, preceded byPS4. the receipts, bestie ๐งพ-o asisโ when quoting output, if you're not in EBCDIC mode andutf8-modeis disabled, show C1 control characters โas isโ โ like, don't escape them. Use this with codepages where the range0x80..0x9Fcontains printable characters (such as437,850,1252, etc. โ but not the ISO 8859 series, for example). ๐-o bgniceโ background jobs get run with lower priority ๐-o braceexpandโ enable brace expansion. On by default, queen behavior ๐-o emacsโ enable BRL emacs-like command-line editing (interactive shells only); see โEmacs editing modeโ. On by default ๐-o gmacsโ enable gmacs-like command-line editing (interactive shells only). Currently identical toemacsediting except thattranspose-chars(^T) acts slightly differently. that's it, that's the whole difference ๐-o ignoreeofโ the shell will not (easily) exit when end-of-file is read; you have to useexit. And to avoid infinite loops, the shell will exit if EOF is read 13 times in a row. thirteen. thirteen chances bestie ๐ญ๐-o inherit-xtraceโ do not reset-o xtraceupon entering functions (default).-o nohupโ do not kill running jobs with aSIGHUPsignal when a login shell exits. Currently enabled by default.-o nologโ no effect. In the original Korn shell, this prevented function definitions from being stored in the history file. so... it's a vibe, not a feature ๐ซ-o physicalโ makes thecdandpwdcommands use โphysicalโ (i.e. the filesystem's) โ..โ directories instead of โlogicalโ directories (i.e. the shell handles โ..โ, which lets the user stay blissfully oblivious to symbolic links to directories). Clear by default. Note that setting this option does not affect the current value of thePWDparameter; only thecdcommand changesPWD. Seecdandpwdabove for more details. ๐ฆ-o pipefailโ make the exit status of a pipeline the rightmost non-zero errorlevel, or zero if all commands exited with zero. finally, pipeline truth ๐ซถ-o posixโ behave closer to the standards (see โPOSIX modeโ for details). Automatically enabled if the shell invocation basename, after โ-โ and โrโ processing, begins with โshโ โ and (often used for thelkshbinary) this autodetection feature is compiled in. As a side effect, setting this flag turns off thebraceexpandflag, which you can turn back on manually, and (unless both are set in the same command)shmode. โ ๏ธ side effects abound, keep an eye on her-o shโ enable kludge/bin/shcompatibility mode (see โSH modeโ below for details). Automatically enabled if the basename of the shell invocation, after โ-โ and โrโ processing, begins with โshโ and this autodetection feature is compiled in (rather uncommon). As a side effect, setting this flag turns off thebraceexpandflag, which can be turned back on manually, andposixmode (unless both are set in the same command). ๐ซ-o viโ enablevi(1)-like command-line editing (interactive shells only). See โVi editing modeโ for documentation and limitations. ๐-o vi-esccompleteโ in vi command-line editing, do command and file name completion whenEsc(^[) is entered in command mode. ๐ง-o vi-tabcompleteโ in vi command-line editing, do command and file name completion whenTab(^I) is entered in insert mode (default). โจ-o virawโ no effect. In the original Korn shell, unlessvirawwas set, the vi command-line mode would let thetty(4)driver do the work untilEscwas entered.mkshis always invirawmode. iconic, she was born that way ๐
These options can also be used upon invocation of the shell. The current set of options with single letter names can be found in the parameter โ$-โ. set -o with no option name will list all the options and whether each one is on or off; set +o prints a command to restore the current option set, using the internal set -o .reset construct, which is an implementation detail โ these commands are transient (only valid within the current shell session). ๐ซง
A lone โ-โ clears both the -v and -x options (obsolete); it (or a lone โ+โ) terminates option processing and is otherwise ignored. ๐
Remaining arguments, if any, are assigned (in order, unless -s is given) to name (with -A) or the positional parameters (i.e., $1, $2, etc). Use -- if the first argument begins with plus or dash. If options end with โ--โ and there are no remaining arguments, all positional parameters are cleared. If no options or arguments are given, the values of all parameters are printed (suitably quoted). ๐
๐ setenv ๐
setenv [name [value]]
(dot.mkshrc function) Without arguments, display the names and values of all exported parameters. Otherwise, set name's export attribute, and its value to value (empty string if none given). she's export with a glow-up โจ
๐ shift ๐
shift [number]
(keeps assignments, special) The positional parameters number+1, number+2, etc. (number defaults to 1) are renamed to 1, 2, etc. sliding down the list like ๐
๐ smores ๐
smores [file ...]
(dot.mkshrc function) Simple pager: Enter next; โqโ+Enter quit. yes, it's named after the snack, she contains multitudes ๐
๐ source ๐
source file [arg ...]
(keeps assignments) Like . (โdotโ), except that the current working directory is appended to the search path. (GNU bash extension) ๐ธ
๐ suspend ๐
(needs job control and getsid(2)) Stops the shell as if it had received the suspend character from the terminal. ๐ด
It is not possible to suspend a login shell unless the parent process is a member of the same terminal session but is a member of a different process group. As a general rule, if the shell was started by another shell or via su(1), it can be suspended. ๐
๐ test ๐
test expression
[ expression ]
(regular) test evaluates the expression and exits with status code 0 if true, 1 if false, or greater than 1 if there was an error. It is often used as the condition command of if and while statements. All file expressions, except -h and -L, follow symbolic links. ๐
The following basic expressions are available:
-a fileโ file exists.-b fileโ file is a block special device.-c fileโ file is a character special device.-d fileโ file is a directory.-e fileโ file exists.-f fileโ file is a regular file.-G fileโ file's group is the shell's effective group ID.-g fileโ file's mode has the setgid bit set.-H fileโ file is a context dependent directory (only useful on HP-UX).-h fileโ file is a symbolic link.-k fileโ file's mode has thesticky(7)bit set.-L fileโ file is a symbolic link.-O fileโ file's owner is the shell's effective user ID.-p fileโ file is a named pipe (FIFO).-r fileโ file exists and is readable.-S fileโ file is aunix(4)-domain socket.-s fileโ file is not empty.-t fdโ File descriptor fd is atty(4)device.-u fileโ file's mode has the setuid bit set.-w fileโ file exists and is writable.-x fileโ file exists and is executable.file1 -nt file2โ file1 is newer than file2, or file1 exists and file2 does not.file1 -ot file2โ file1 is older than file2, or file2 exists and file1 does not.file1 -ef file2โ file1 is the same file as file2.stringโ string has non-zero length.-n stringโ string is not empty.-z stringโ string is empty.-v nameโ The shell parameter name is set.-o optionโ Shell option is set (see thesetcommand above for a list of options). As a non-standard extension, if the option starts with a โ!โ, the test is negated; the test always fails if option doesn't exist (so[ -o foo -o -o !foo ]returns true if and only if optionfooexists). The same can be achieved with[ -o ?foo ]like in AT&T UNIXksh93. option can also be the short flag prefixed with either โ-โ or โ+โ (no logical negation), for example โ-xโ or โ+xโ instead of โxtraceโ. ๐ฅstring = stringโ the two strings are equal, periodt โจ. In double brackets, pattern matching happens (R59+ using extglobs) if the right-hand string isn't quoted.string == stringโ same thing as=, but deprecated bestie, so use=instead ๐ .string != stringโ nope, not equal ๐ . See=above for the whole pattern matching situation.string > stringโ first string operand is greater than the second one.string < stringโ first string operand is less than the second one.number -eq numberโ numbers compare equal ๐.number -ne numberโ numbers compare not equal.number -ge numberโ numbers compare greater than or equal.number -gt numberโ numbers compare greater than.number -le numberโ numbers compare less than or equal.number -lt numberโ numbers compare less than.
All those basic expressions above? Unary operators have precedence over binary operators, and you can vibe them together with these (listed in increasing order of precedence, so the strongest one goes last):
expr -o exprโ Logical OR.expr -a exprโ Logical AND.! exprโ Logical NOT.( expr )โ Grouping.
Lowkey important: a number can literally be an arithmetic expression, like a mathematical term or the name of an integer variable ๐ง :
x=1; [ "x" -eq 1 ] evaluates to true
Also note that some special rules kick in (courtesy of POSIX, of course ๐) when the number of arguments to test or inside the brackets [ ... ] is less than five: if leading ! arguments can be stripped such that only one to three arguments remain, then the lowered comparison is executed; (thanks to XSI) parentheses \( ... \) lower four- and three-argument forms to two- and one-argument forms, respectively; three-argument forms ultimately prefer binary operations, followed by negation and parenthesis lowering; two- and four-argument forms prefer negation followed by parenthesis; the one-argument form always implies -n. To assume this is not necessarily portable ๐.
Note: a super common mistake is usingif [ $foo = bar ], which fails if the parameterfoois empty or unset, if it has embedded spaces (i.e.IFSoctets), or if it's a unary operator like!or-n. Use tests likeif [ x"$foo" = x"bar" ]instead, or the double-bracket construct (see[[above):if [[ $foo = bar ]]or, to avoid pattern matching,if [[ $foo = "$bar" ]]. The[[ ... ]]construct is not only more secure to use but also often faster ๐ฅ. Similarly, operators need to be quoted as usual fortest/[.
time [-p] [pipeline]
(reserved word) ๐ฐ๏ธ If you hand it a pipeline, the times used to execute that pipeline get reported. If you hand it nothing, then the user and system time used by the shell itself โ plus all the commands it has run since it started โ get reported.
The times reported are the real time (elapsed time from start to finish), the user CPU time (time spent running in user mode), and the system CPU time (time spent running in kernel mode) ๐ซ.
Times are reported to standard error, and the format of the output is:
0m0.03s real 0m0.02s user 0m0.01s system
If the -p option is given (which is only permitted if pipeline is a simple command), the output is slightly longer:
real 0.03
user 0.02
sys 0.01
Simple redirections of standard error do not affect time's output, bestie:
$ time sleep 1 2>afile
$ { time sleep 1; } 2>afile
Times for the first command do not go to afile, but those of the second command do. Main character behaviour tbh ๐ธ.
times
(keeps assignments, special) Print the accumulated user and system times (see above โฌ๏ธ) used both by the shell and by processes that the shell started which have exited. The format of the output is:
0m0.01s 0m0.00s
0m0.04s 0m0.02s
trap n [signal ...]
(keeps assignments, special) If the first operand is a decimal unsigned integer, this resets all specified signals to the default action โ i.e. it's the same as calling trap with a dash (-) as the handler, followed by the arguments (interpreted as signals).
trap handler signal ...
(keeps assignments, special) Sets a trap handler that gets run when any of the specified signals are received ๐จ. handler is either an empty string, meaning the signals are to be ignored, a dash (-), meaning that the default action is to be taken for the signals (see signal(3)), or a string made of shell commands to be executed at the first opportunity (i.e. when the current command completes or before printing the next PS1 prompt) after one of the signals is received. signal is the name, possibly prefixed with SIG, of a signal (e.g. PIPE, ALRM or SIGINT) or the number of the signal (see the kill -l command above) ๐.
There are two special signals: EXIT (also known as 0), which runs when the shell is about to exit, and ERR, which runs after an error occurs; an error is something that would cause the shell to exit if the set -e or set -o errexit option were set. EXIT handlers are executed in the environment of the last executed command. The original Korn shell's DEBUG trap and handling of ERR and EXIT in functions are not yet implemented ๐.
Note that, for non-interactive shells, the trap handler cannot be changed for signals that were ignored when the shell started. That's just how it is ๐.
trap [-p [signal ...]]
With no arguments, the current state of the traps that have been set since the shell started is shown as a series of trap commands โจ. With -p, the state of all traps (or all listed traps) is shown, not just modified traps; this is useful to save and later restore the current state of traps.
Heads up: the output of trap cannot be easily captured or piped to another process (an artifact of the fact that traps are cleared when subprocesses are created ๐ญ). Using ksh93-style funsubs works though:
save_traps=${ trap -p;}
# ...
eval "$save_traps"
SIGKILL, SIGSTOP and some OS-specific signals (such as 32 and 33 on GNU/Linux) cannot be trapped ๐ซ. Attempts are normally silently ignored; the output of trap -p does not necessarily reflect this.
true
(regular) A command that exits with a zero status. Just vibes, no output, immaculate โ .
type name ...
(built-in alias) Reveal how name would be interpreted as a command ๐.
typeset [-+aglpnrtUux] [-L[n] | -R[n] | -Z[n]] [-i[n]] [name[=value] ...]
typeset -f [-tux] [name ...]
(keeps assignments, decl-util) Display or set attributes of shell parameters or functions ๐. With no name arguments, parameter attributes are shown; if no options are used, the current attributes of all parameters are printed as typeset commands; if an option is given (or - with no option letter), all parameters and their values with the specified attributes are printed; if options are introduced with + (or + alone), only names are printed.
If any name arguments are given, the attributes of the so named parameters are set (-) or cleared (+); inside a function, this will cause the parameters to be created (and set to "" if no value is given) in the local scope (except if -g is used). Values for parameters may optionally be specified. For name[*], the change affects all elements of the array, and no value may be specified โจ.
When -f is used, typeset operates on the attributes of functions ๐
. As with parameters, if no name arguments are given, functions are listed with their values (i.e. definitions) unless options are introduced with +, in which case only the names are displayed.
-aโ Indexed array attribute.-fโ Function mode. Display or set shell functions and their attributes, instead of shell parameters.-gโ "global" mode. Do not cause named parameters to be created in the local scope when called inside a function ๐.-i[n]โ Integer attribute. n specifies the base to use when stringifying the integer (if not specified, the base given in the first assignment is used). Parameters with this attribute may be assigned arithmetic expressions for values.-L[n]โ Left justify attribute. n specifies the field width. If n is not specified, the current width of the parameter (or the width of its first assigned value) is used. Leading whitespace (and digit zeros, if used with the-Zoption) is stripped. If necessary, values are either truncated or padded with space to fit the field width.-lโ Lower case attribute. All upper case ASCII characters in values are converted to lower case. (In the original Korn shell, this parameter meant "long integer" when used with the-ioption ๐ซ .)-nโ Create a bound variable (name reference): any access to the variable name will access the variable value in the current scope (this is different from AT&T UNIX ksh93!) instead ๐ณ. Also different from AT&T UNIX ksh93 is that value is lazily evaluated at the time name is accessed. This can be used by functions to access variables whose names are passed as parameters, instead of resorting toeval.-pโ Print completetypesetcommands that can be used to re-create the attributes and values of parameters.-R[n]โ Right justify attribute. n specifies the field width. If n is not specified, the current width of the parameter (or the width of its first assigned value) is used. Trailing whitespace is stripped. If necessary, values are either stripped of leading characters or padded with space to fit the field width.-rโ the read-only attribute ๐ parameters rockin' this one cannot be assigned to and cannot be unset. And once you turn it on?? That's it, bestie, it is never coming off. no takebacks.-tโ the tag attribute โจ for parameters it literally means nothing to the shell, it's just there so your app can use it.
For functions tho, -t is the trace attribute ๐ฆ โ when a function with the trace attribute runs, the -o xtrace (-x) shell option gets temporarily turned on. it's giving "watch me work".
-Uโ the unsigned integer attribute. integers get printed as unsigned values (it's combined with the-ioption).-uโ the upper case attribute ๐ธ all lower case ASCII characters in values get converted to UPPER CASE. (fun fact: in the original Korn shell this parameter meant "unsigned integer" when used with-i, which meant upper case letters would never be used for bases greater than 10. see-Uabove, she's the upgraded version.)
For functions, -u is the undefined attribute, used with FPATH. check "Functions" above for what that actually implies ๐
-xโ the export attribute. parameters get dropped into the environment of any executed commands. functions cannot be exported tho, for security reasons ("shellshock") ๐-Z[n]โ the zero fill attribute. if it's not combined with-L, it's the same as-R, except zero padding is used instead of space padding. for integers, it's the number that gets padded, not the base โญ
okay important one: if any of the-i,-L,-l,-R,-U,-uor-Zoptions are changed, all the others from that set get cleared โ unless you also gave them on the same command line. so don't come crying to me when half your attributes ghosted you ๐
๐ ulimit ๐
ulimit [-aBCcdefHilMmnOPpqrSsTtVvwx] [value]
(regular) Display or set process limits ๐ If you don't use any options, the file size limit (-f) is assumed. value, if you give one, can be either an arithmetic expression or the word "unlimited". These limits affect the shell and any processes the shell creates after a limit is imposed. heads up: systems may not let you increase some limits once they're set ๐ญ Also note that which limits even exist is system dependent โ some systems have only the -f limit, or not even that, or can only set the soft limits, etc. so vibe check your OS first.
-aโ display all limits (soft limits unless you use-H).-B nโ set the socket buffer size to n kibibytes.-C nโ set the number of cached threads to n.-c nโ impose a size limit of n blocks on the size of core dumps. silently ignored if the system doesn't support this limit ๐คทโโ๏ธ-d nโ limit the size of the data area to n kibibytes. on some systems, read-only maximumbrk(2)size minusetext.-e nโ set the maximum niceness to n.-f nโ impose a size limit of n blocks on files written by the shell and its child processes (any size may be read).-Hโ set the hard limit only (the default is to set both hard and soft limits). with-a, display all hard limits.-i nโ set the number of pending signals to n.-l nโ impose a limit of n kibibytes on the amount of locked (wired) physical memory.-M nโ set the AIO locked memory to n kibibytes.-m nโ impose a limit of n kibibytes on the amount of physical memory used.-n nโ impose a limit of n file descriptors that can be open at once. on some systems attempts to set this are silently ignored ๐-O nโ set the number of AIO operations to n.-P nโ limit the number of threads per process to n.
this option mostly matches AT&T UNIX ksh93's -T; on AIX, check -r as used by its ksh tho.
-p nโ impose a limit of n processes that can be run by the user (uid) at any one time.-q nโ limit the size of POSIX message queues to n bytes.-R nโ (Linux) limit the CPU time slice a real-time process can use before performing a blocking syscall to n milliseconds.-r nโ (AIX) limit the number of threads per process to n. (Linux) set the maximum real-time priority to n.-Sโ set the soft limit only (the default is to set both hard and soft limits). with-a, display soft limits (that's the default).-s nโ limit the size of the stack area to n kibibytes.-T nโ impose a time limit of n real seconds ("humantime") to be used by each process.-t nโ impose a time limit of n CPU seconds spent in user mode to be used by each process.-V nโ set the number of vnode monitors on Haiku to n.-v nโ impose a limit of n kibibytes on the amount of virtual memory (address space) used.-w nโ limit the amount of swap space used to at most n kibibytes.-x nโ set the maximum number of file locks to n.
and as far as ulimit is concerned?? a block is 512 bytes. periodt.
๐ umask ๐
umask [-S] [mask]
(regular) Display or set the file permission creation mask, aka the umask (see umask(2)). if you use the -S option, the mask you display or set is symbolic; otherwise it's an octal number.
Symbolic masks are like the ones chmod(1) uses ๐
When you use them, they describe what permissions may be made available (as opposed to octal masks, where a set bit means the corresponding bit is to be cleared). for example, ug=rwx,o= sets the mask so files will not be readable, writable or executable by "others", and it's equivalent (on most systems) to the octal mask 007. iconic behavior honestly.
๐ unalias ๐
unalias [-adt] [name ...]
(regular) The aliases for the given names get removed ๐ซถ if you use the -a option, all aliases get removed. if you use the -t or -d options, the indicated operations are carried out on tracked or directory aliases, respectively.
๐ฆ unset ๐ฆ
unset [-fv] parameter ...
(keeps assignments, special) Unset the named parameters (-v, the default) or functions (-f). with parameter[*], attributes are retained and only values get unset. the exit status is non-zero if any of the parameters are read-only, zero otherwise โ and btw that part is not portable ๐
โจ wait โจ
wait [job ...]
(regular) Wait for the specified job(s) to finish โณ the exit status of wait is that of the last specified job; if the last job is killed by a signal, the exit status is 128 + the signal number (see kill -l exit-status above); if the last specified job can't be found (because it never existed or had already finished), the exit status is 127. see "Job control" below for the format of job. wait will return if a signal for which a trap has been set is received, or if a SIGHUP, SIGINT or SIGQUIT signal is received.
If no jobs are specified, wait waits for all currently running jobs (if any) to finish and exits with a zero status. if job monitoring is enabled, the completion status of jobs gets printed โ and no, that is not the case when jobs are explicitly specified ๐
โโ๏ธ
๐ whence ๐
whence [-pv] [name ...]
(regular) Without the -v option, it's the same as command -v, except aliases are printed as their definition only. with the -v option, it's exactly identical to command -V. either way, with the -p option the search is restricted to the (current) PATH.
๐ which ๐
which [-a] [name ...]
(dot.mkshrc function) Without -a, it behaves like whence -p (does a PATH search for each name, printing the resulting pathname if found); with -a, matches in all PATH components are printed, i.e. the search isn't stopped after a match ๐ฅ if no name was matched, the exit status is 2; if every name was matched, it's zero; otherwise it's 1. and no diagnostics are produced on failure to match. silent treatment fr fr.
๐ Job control ๐
Job control refers to the shell's ability to monitor and control jobs, which are processes or groups of processes created for commands or pipelines. At a minimum, the shell keeps track of the status of the background (i.e. asynchronous) jobs that currently exist; you can display this info with the jobs commands ๐ if job control is fully enabled (using set -m or set -o monitor), like it is for interactive shells, the processes of a job get placed in their own process group. foreground jobs can be stopped by typing the suspend character from the terminal (normally ^Z); jobs can be restarted in either the foreground or background using the commands fg and bg ๐โโ๏ธ
Note that only commands that create processes (e.g. asynchronous commands, subshell commands and non-built-in, non-function commands) can be stopped; commands like read cannot be. sorry bestie, that one's just not stoppable ๐ญ
When a job is created, it's assigned a job number. for interactive shells, this number is printed inside "[...]", followed by the process IDs of the processes in the job, whenever an asynchronous command is run. A job may be referred to in the bg, fg, jobs, kill and wait commands either by the process ID of the last process in the command pipeline (as stored in the $! parameter) or by prefixing the job number with a percent sign (%). other percent sequences can also be used to refer to jobs:
%+ | %% | %โ the most recently stopped job or, if there are no stopped jobs, the oldest running job. main character of the job list ๐%-โ the job that would be the%+job if the latter did not exist. (so, the runner-up ๐ธ)%nโ the job with job number n.%?stringโ the job with its command containing the string string (an error occurs if multiple jobs are matched).%stringโ the job with its command starting with the string string (an error occurs if multiple jobs are matched).
When a job changes state (e.g. a background job finishes or a foreground job is stopped), the shell prints the following status information:
[number] flag status command
where...
number โ is the job number of the job;
flag โ is the + or - character if the job is the %+ or %- job, respectively, or a space if it's neither;
status โ indicates the current state of the job and can be:
Done [number]โ the job exited. number is the exit status of the job, which is omitted if the status is zero.- Running โ the job has neither stopped nor exited. (And bestie, heads up: "running" does not necessarily mean it's consuming CPU time โ the process could be blocked, waiting for some event.) ๐ซถ
- Stopped [signal] โ the job was stopped by the signal it names. If no signal is given there, then the job was stopped by
SIGTSTP. - signal-description ["core dumped"] โ the job was killed by a signal (memory fault, hangup, that whole genre); use
kill -lfor a list of signal descriptions. The"core dumped"message means the process created a core file. ๐ commandis the command that created the process. If there are multiple processes in the job, each process will have a line showing its command and possibly its status, if it is different from the status of the previous process.
When you try to exit the shell while there are jobs in the stopped state, the shell warns you that there are stopped jobs and does not exit. But if you immediately try to exit again? The stopped jobs get sent a SIGHUP and the shell exits. ๐ญ Same energy with login shells: if the nohup option is not set and there are running jobs when you attempt to exit a login shell, the shell warns you and does not exit โ and if you immediately try again, those running jobs get a SIGHUP and the shell exits.
๐ป Terminal state
The state of the controlling terminal can be modified by a command executed in the foreground, whether or not job control is enabled โ but the modified terminal state is only kept past the job's lifetime, and used for later command invocations, if the command exits successfully (i.e. with an exit status of 0). When such a job is momentarily stopped or restarted, the terminal state is saved and restored, respectively, but it will not be kept afterwards. And in interactive mode, when line editing is enabled, the terminal state is saved before being reconfigured by the shell for the line editor, then restored before running a command. Obsessed with the tidiness actually. โจ
๐งพ POSIX mode
Entering set -o posix mode will cause mksh to behave even more POSIX compliant in places where the defaults or opinions differ. Note that mksh will still operate with unsigned 32-bit arithmetic; use lksh if arithmetic on the host long data type โ complete with ISO C Undefined Behaviour โ is required; refer to the lksh(1) manual page for details. Most other historic, AT&T UNIX ksh-compatible or opinionated differences can be disabled by using this mode; these are:
- The incompatible GNU
bashI/O redirection&>fileis not supported. - File descriptors created by I/O redirections are inherited by child processes.
- Numbers with a leading digit zero are interpreted as octal.
- The
echobuiltin does not interpret backslashes and only supports the exact option-n. - Alias expansion with a trailing space only reruns on command words.
- Tilde expansion follows POSIX instead of Korn shell rules.
- The exit status of
fgis always0. kill -lonly lists signal names, all in one line.getoptsdoes not accept options with a leading โ+โ.execskips builtins, functions and other commands and uses aPATHsearch to determine the utility to execute. Interactive shells do not exit on failure (note: the execution environment may be tainted).
๐ SH mode
Compatibility mode; intended for use with legacy scripts that cannot easily be fixed; the changes are as follows:
- The incompatible GNU
bashI/O redirection&>fileis not supported. - File descriptors created by I/O redirections are inherited by child processes.
- The
echobuiltin does not interpret backslashes and only supports the exact option-n, unless built with-DMKSH_MIDNIGHTBSD01ASH_COMPAT. - The substitution operations
${x#pat},${x##pat},${x%pat}, and${x%%pat}wrongly do not require a parenthesis to be escaped and do not parse extglobs. - The
getoptconstruct fromlksh(1)passes through the errorlevel. sh -ceats a leading--if built with-DMKSH_MIDNIGHTBSD01ASH_COMPAT.
๐ Interactive input line editing
The shell supports three modes of reading command lines from a tty(4) in an interactive session, controlled by the emacs, gmacs and vi options (at most one of these can be set at once). The default is emacs. Editing modes can be set explicitly using the set built-in. If none of these options are enabled, the shell simply reads lines using the normal tty(4) driver. If the emacs or gmacs option is set, the shell allows emacs-like editing of the command; similarly, if the vi option is set, the shell allows vi-like editing of the command. These modes are described in detail in the following sections.
In these editing modes, if a line is longer than the screen width (see the COLUMNS parameter), a โ>โ, โ+โ or โ<โ character is displayed in the last column indicating that there are more characters after, before and after, or before the current position, respectively. The line is scrolled horizontally as necessary. ๐
Completed lines are pushed into the history, unless they begin with an IFS octet or IFS white space or are the same as the previous line.
๐ธ Emacs editing mode
When the emacs option is set, interactive input line editing is enabled. Warning: This mode is slightly different from the emacs mode in the original Korn shell. In this mode, various editing commands (typically bound to one or more control characters) cause immediate actions without waiting for a newline. Several editing commands are bound to particular control characters when the shell is invoked; these bindings can be changed using the bind command.
The following is a list of available editing commands. Each description starts with the name of the command, suffixed with a colon; a [n] (if the command can be prefixed with a count); and any keys the command is bound to by default, written using caret notation (e.g. the ASCII Esc character is written as ^[) or terminal-specific indications. A count prefix for a command is entered using the sequence ^[n, where n is one or more digits. Unless otherwise specified, if a count is omitted, it defaults to 1.
Bigwords, as used below, are separated by spaces or tabs; words consist of alphanumerics, underscore (โ_โ) or dollar sign (โ$โ) characters.
Note that editing command names are used only with thebindcommand. Furthermore, many editing commands are useful only on terminals with a visible cursor. The user'stty(4)characters (e.g.ERASE) are bound to reasonable substitutes and override the default bindings; their customary values are shown in parentheses below. The default bindings were chosen to resemble corresponding Emacs key bindings: ๐
abort:INTR(^C),^Gโ Abort the current command, save it to the history, empty the line buffer and set the exit state to interrupted.auto-insert:[n]โ (Most ordinary characters are bound to this command.) Simply causes the character to appear as literal input.backward-bigword:[n]^[Bโ Moves the cursor backward to the beginning of the bigword.backward-char:[n]^B,^XD,ANSI-CurLeft,PC-CurLeftโ Moves the cursor backward n characters.backward-word:[n]^[b,ANSI-Ctrl-CurLeft,ANSI-Alt-CurLeftโ Moves the cursor backward to the beginning of the word.beginning-of-history:^[<โ Moves to the beginning of the history.beginning-of-line:^A,ANSI-Home,PC-Homeโ Moves the cursor to the beginning of the edited input line.capitalise-bigword:[n]^[Cโ Uppercase the first character in the next n bigwords as below.capitalise-word:[n]^[cโ Uppercase the first ASCII character in the next n words, leaving the cursor past the end of the last word.clear-screen:^[^Lโ Prints a compile-time configurable sequence to clear the screen and home the cursor, redraws the last line of the prompt string and the currently edited input line. The default sequence works for almost all standard terminals.comment:^[#โ If the current line does not begin with a comment character, one is added at the beginning of the line and the line is entered (as if return had been pressed); otherwise, the existing comment characters are removed and the cursor is placed at the beginning of the line. Does not update the mark.complete:^[^[โ Automatically completes as much as is unique of the command name or the file name containing the cursor. If the entire remaining command or file name is unique, a space is printed after its completion, unless it is a directory name in which case โ/โ is appended. If there is no command or file name with the current partial word as its prefix, a bell character is output (usually causing a beep to be sounded).complete-command:^X^[โ Automatically completes as much as is unique of the command name having the partial word up to the cursor as its prefix, as in thecompletecommand above.complete-file:^[^Xโ Automatically completes as much as is unique of the file name having the partial word up to the cursor as its prefix, as in thecompletecommand described above.complete-list:^I,^[=โ Complete as much as is possible of the current word and list the possible completions for it. If only one completion is possible, match as in thecompletecommand above. Note that^Iis usually generated by the Tab (tabulator) key.delete-bigword-backward:[n]^[Hโ Deletes n bigwords before the cursor.delete-bigword-forward:[n]^[Dโ Deletes characters after the cursor up to the end of n bigwords.delete-char-backward:[n]ERASE(^H),^?,^Hโ Deletes n characters before the cursor.delete-char-forward:[n]ANSI-Del,PC-Delโ Deletes n characters after the cursor.delete-word-backward:[n]Pfx1+ERASE(^[^H),WERASE(^W),^[^?,^[^H,^[hโ Deletes n words before the cursor.delete-word-forward:[n]^[dโ Deletes characters after the cursor up to the end of n words.down-history:[n]^N,^XB,ANSI-CurDown,PC-CurDownโ Scrolls the history buffer forward n lines (later). Each input line originally starts just after the last entry in the history buffer, sodown-historyis not useful until eithersearch-history,search-history-uporup-historyhas been performed.downcase-bigword([n]^[L) โ lowercases the next n bigwords. no shouting bestie ๐downcase-word([n]^[l) โ lowercases the next n words.edit-line([n]^Xe) โ internally runsfc -e "${VISUAL:-${EDITOR:-vi}}" -- nagainst a temp script file so you can edit line n by hand (or the current line if you don't give an n), and then โ unless the editor you launched exits nonzero โ it runs the resulting script as if you'd typed it right there on the command line. note that this happens even if the script didn't actually change, and both the edited/resulting line AND the original line get dropped onto history. girl keeps the receipts ๐end-of-history(^[>) โ teleports to the end of the history. the very end. periodt.end-of-line(^E,ANSI-End,PC-End) โ cursor to the end of the input line.eot(^_) โ acts as an end-of-file. lowkey useful because edit-mode input disables normal terminal input canonicalisation. โจeot-or-delete([n]EOF (^D)) โ if you're all alone on a line, it's the same aseot; otherwise it'sdelete-char-forward.error(not bound) โ errors out. aka rings the bell. ๐evaluate-region(^[^E) โ evaluates the text between the mark and the cursor position (or the entire line if there's no mark) as function substitution. if it can't be parsed, the editing state stays exactly as it was and the bell rings to tell you it's mad.$?gets updated accordingly. ๐exchange-point-and-mark(^X^X) โ puts the cursor where the mark is and sets the mark to where the cursor used to be. swapping besties ๐ซถexpand-file(^[*) โ appends a*to the current word and replaces the word with whatever you get from file globbing on it. if nothing matches the pattern: bell. ๐forward-bigword([n]^[F) โ cursor forward to the end of the *n*th bigword.forward-char([n]^F,^XC,ANSI-CurRight,PC-CurRight) โ cursor forward n characters.forward-word([n]^[f,ANSI-Ctrl-CurRight,ANSI-Alt-CurRight) โ cursor forward to the end of the *n*th word.goto-history([n]^[g) โ goes straight to history number n. skipping the line fr.kill-line(KILL (^U)) โ deletes the entire input line and unsets the mark.kill-region(^[^W) โ deletes the input between the cursor and the mark. note: this used to be bound to^Wlike in Emacs, except^Wis usually taken byWERASE, so it got moved. it's giving relocation era ๐ฆkill-to-eol([n]^K) โ with no n, deletes the input from the cursor to the end of the line. with an n, it deletes the characters between the cursor and column n.list(^[?) โ prints a sorted, columnated list of the command names or file names (if any) that could complete the partial word containing the cursor. directory names get a/tacked onto them.list-command(^X?) โ prints a sorted, columnated list of the command names (if any) that could complete the partial word containing the cursor.list-file(^X^Y) โ prints a sorted, columnated list of the file names (if any) that could complete the partial word containing the cursor. file type indicators get appended just like underlistabove.newline(^J,^M) โ causes the current input line to be processed by the shell. your cursor can be anywhere on the line, no stress.newline-and-next(^O) โ processes the current input line with the shell, and then the next line from history becomes the current line. this is only useful after anup-history,search-historyorsearch-history-up. quotidian queen ๐no-op(QUIT (^\)) โ does absolutely nothing. main character energy of just existing โจprefix-1(^[) โ introduces a 2-character command sequence.prefix-2(^X,^[[,^[O) โ introduces a multi-character command sequence.prefix-3(^@) โ introduces a PC keyboard scancode.prev-hist-bigword([n]^[.,^[_) โ with no count, the last bigword from the previous line gets inserted at the cursor; with a count, it's the *(n+1)*th bigword, and the mark is set to the beginning of the inserted word. invoke it over and over and the inserted text gets replaced by the matching bigword from the second-last, third-last, etc. line. time travel but make it text ๐ฆquote(^^,^V) โ the next character is taken literally instead of being read as an editing command.quote-region(^[Q) โ escapes the text between the mark and the cursor position (or the entire line if there's no mark) into a shell command argument.redraw(^L) โ reprints the last line of the prompt string and the current input line, on a new line.search-character-backward([n]^[^]) โ search backward in the current line for the *n*th occurrence of the next character you type.search-character-forward([n]^]) โ search forward in the current line for the *n*th occurrence of the next character you type.search-history(^R) โ enter incremental search mode. the internal history list is searched backwards for commands matching your input. an initial^in the search string anchors the search at the beginning of the line. the escape key leaves search mode. other commands โ including sequences of escape asprefix-1followed by aprefix-1orprefix-2key โ get executed after leaving search mode. the abort (^G) command restores the input line from before the search started. successivesearch-historycommands keep searching backward to the next previous occurrence of the pattern. heads up: the history buffer only retains a finite number of lines, and the oldest ones get discarded as necessary. ๐search-history-down(ANSI-PgDn,PC-PgDn) โ search forwards (this command is only useful after anup-history,search-history-uporsearch-history) through the history buffer for commands whose beginning matches the portion of the input line before the cursor. on an empty line it does the same thing asdown-history.search-history-up(ANSI-PgUp,PC-PgUp) โ search backwards through the history buffer for commands whose beginning matches the portion of the input line before the cursor. on an empty line it does the same thing asup-history.set-arg(^[0..^[9) โ mapped to begin prefixing a count to a command. numbers era ๐ขset-mark-command(^[then Space) โ set the mark at the cursor position.transpose-chars(^T) โ if you're at the end of line, or if thegmacsoption is set, this exchanges the two previous characters; otherwise it exchanges the previous and current characters and moves the cursor one character to the right. swappy ๐up-history([n]^P,^XA,ANSI-CurUp,PC-CurUp) โ scrolls the history buffer backward n lines (earlier).upcase-bigword([n]^[U) โ uppercases the next n bigwords. SCREAMING ๐upcase-word([n]^[u) โ uppercases the next n words.version(^[^V) โ displays the version ofmksh. the current edit buffer is restored as soon as you press a key. that restoring keypress gets processed, unless it's a space.vt100-hack(^[[1) โ mapped to internally represent some longer key sequences.yank(^Y) โ inserts the most recently killed text string at the current cursor position.yank-pop(^[y) โ immediately after ayank, replaces the inserted text string with the next previously killed text string.
tab completion escapes characters the same way as the following code:
print -nr -- "${x@/[\"-\$\&-*:-?[\\\`\{-\~${IFS-$' \t\n'}]/\\$KSH_MATCH}"
๐ฆ Vi editing mode ๐ฆ
note: the vi command-line editing mode has not yet been brought up to the same quality and feature set as the emacs mode. it is 8-bit clean, but it specifically does not support UTF-8 or MBCS. bestie, it's giving work-in-progress ๐
the vi command-line editor in mksh has basically the same commands as the vi(1) editor, with the following exceptions:
- you start out in insert mode.
- there are file name and command completion commands:
=,\,*,^X,^E,^Fand, optionally, Tab and Esc. - the
_command is different (inmkshit's the last argument command; invi(1)it goes to the start of the current line). - the
/andGcommands move in the opposite direction to thejcommand. - commands which don't make sense in a single line editor aren't available (e.g. screen movement commands and
ex(1)-style colon (:) commands).
like vi(1), there are two modes: โinsertโ mode and โcommandโ mode. in insert mode, most characters are just simply put in the buffer at the current cursor position as you type them; but some characters are treated specially. in particular, the following characters come from the current tty(4) settings (see stty(1)) and keep their usual meaning (normal values in parentheses): kill (^U), erase (^?), werase (^W), eof (^D), intr (^C) and quit (^\). on top of all that, these characters are also treated specially in insert mode:
^Eโ command and file name enumeration (see below).^Fโ command and file name completion (see below). used twice in a row, the list of possible completions gets displayed; used a third time, the completion is undone.^Hโ erases previous character.^J|^Mโ end of line. the current line is read, parsed and executed by the shell.^Vโ literal next. the next character typed isn't treated specially (great for inserting the very characters being described here ๐ซถ).^Xโ command and file name expansion (see below).<Esc>โ puts the editor in command mode (see below).<Tab>โ optional file name and command completion (see^Fabove), enabled withset -o vi-tabcomplete.
in command mode, every character is interpreted as a command. characters that don't correspond to commands, illegal combinations of commands, or commands that can't be carried out โ all of them cause beeps. ๐ in the following command descriptions, an [n] means the command may be prefixed by a number (e.g. 10l moves right 10 characters); if no number prefix is used, n is assumed to be 1 unless otherwise specified. the term โcurrent positionโ refers to the position between the cursor and the character preceding the cursor. a โwordโ is a sequence of letters, digits and underscore characters, or a sequence of non-letter, non-digit, non-underscore and non-whitespace characters (e.g. ab2*&^ contains two words), and a โbig-wordโ is a sequence of non-whitespace characters.
โจ Special mksh vi commands โจ
the following commands are not in, or are different from, the normal vi file editor:
[n]_โ drops a space plus the nth big-word from the last command in your history right at the current position, then yeets you into insert mode โจ if n isn't given, it's the last word that gets inserted.#โ puts the comment character (#) at the start of the current line and hands the line back to the shell (it's literally the same asI#^J). periodt.[n]gโ likeG, except when n isn't specified it goes to the most recent remembered line.[n]vโ internally runs this command, bestie:
fc -e "${VISUAL:-${EDITOR:-vi}}" -- n
on a temporary script file, so you interactively edit line n (or the current line if n isn't specified); then โ unless whatever editor got invoked exits nonzero, but even if the script wasn't changed โ it executes the resulting script as if you'd typed it straight onto the command line; both the edited (resulting) and original lines get added onto history. ๐
*and^Xโ command or file name expansion gets applied to the current big-word (with a*appended if the word has no file globbing characters in it) โ and the big-word gets replaced with the resulting words. Okay so here's the vibe check: if the current big-word is the first one on the line, or it follows one of the characters;,|,&,(or), and it does not contain a slash (/), then command expansion is what happens; otherwise it's file name expansion. Command expansion matches the big-word against all aliases, functions and built-in commands, plus any executable files it finds by searching the directories in thePATHparameter. File name expansion matches the big-word against the files in the current directory. After expansion, the cursor is placed just past the last word and the editor is in insert mode. iconic behavior ๐ซถ[n]\,[n]^F,[n]<Tab>, and[n]<Esc>โ command/file name completion. Replaces the current big-word with the longest unique match obtained after performing command and file name expansion.<Tab>is only recognised if thevi-tabcompleteoption is set, while<Esc>is only recognised if thevi-esccompleteoption is set (seeset -o). If n is specified, the *n*th possible completion is selected (as reported by the command/file name enumeration command).=and^Eโ command/file name enumeration. Lists all the commands or files that match the current big-word. no cap ๐^Vโ displays the version ofmksh. The current edit buffer is restored as soon as a key is pressed. The restoring keypress is ignored.@cโ macro expansion. Executes the commands found in the alias_c.
๐ผ Intra-line movement commands
[n]hand[n]^Hโ move left n characters.[n]land[n]<space>โ move right n characters.0โ move to column 0.^โ move to the first non-whitespace character.[n]|โ move to column n.$โ move to the last character.[n]bโ move back n words.[n]Bโ move back n big-words.[n]eโ move forward to the end of the word, n times.[n]Eโ move forward to the end of the big-word, n times.[n]wโ move forward n words.[n]Wโ move forward n big-words.%โ find match. The editor looks forward for the nearest parenthesis, bracket or brace and then moves the cursor to the matching parenthesis, bracket or brace. matching energy fr fr ๐[n]fcโ move forward to the nth occurrence of the character c.[n]Fcโ move backward to the nth occurrence of the character c.[n]tcโ move forward to just before the nth occurrence of the character c.[n]Tcโ move backward to just before the nth occurrence of the character c.[n];โ repeats the lastf,F,torTcommand.[n],โ repeats the lastf,F,torTcommand, but moves in the opposite direction.
๐ Inter-line movement commands
[n]j,[n]+, and[n]^Nโ move to the *n*th next line in the history.[n]k,[n]-, and[n]^Pโ move to the *n*th previous line in the history.[n]Gโ move to line n in the history; if n isn't specified, the number of the first remembered line is used.[n]gโ likeG, except if n isn't specified, it goes to the most recent remembered line.[n]/stringโ search backward through the history for the nth line containing string; if string starts with^, the rest of the string has to appear at the start of the history line for it to match.[n]?stringโ same as/, except it searches forward through the history.[n]nโ search for the *n*th occurrence of the last search string; the direction of the search is the same as the last search.[n]Nโ search for the *n*th occurrence of the last search string; the direction of the search is the opposite of the last search.ANSI-CurUp,PC-PgUpโ take the characters from the beginning of the line to the current cursor position as a search string and do a history search, backwards, for lines beginning with this string; keep the cursor position. Heads up: this works only in insert mode and keeps it enabled.ANSI-CurDown,PC-PgDnโ take the characters from the beginning of the line to the current cursor position as a search string and do a history search, forwards, for lines beginning with this string; keep the cursor position. This too only works in insert mode and keeps it enabled.
โ๏ธ Edit commands
[n]aโ append text n times; goes into insert mode just after the current position. The append is only replicated if command mode is re-entered, i.e.<Esc>is used.[n]Aโ same asa, except it appends at the end of the line.[n]iโ insert text n times; goes into insert mode at the current position. The insertion is only replicated if command mode is re-entered, i.e.<Esc>is used.[n]Iโ same asi, except the insertion is done just before the first non-blank character.[n]sโ substitute the next n characters (so: delete the characters and go into insert mode).Sโ substitute whole line. All characters from the first non-blank character to the end of the line are deleted and insert mode is entered.[n]cmove-cmdโ change from the current position to the position resulting from n move-cmds (so: delete the indicated region and go into insert mode); if move-cmd isc, the line starting from the first non-blank character is changed.Cโ change from the current position to the end of the line (so: delete to the end of the line and go into insert mode).[n]xโ delete the next n characters.[n]Xโ delete the previous n characters.Dโ delete to the end of the line.[n]dmove-cmdโ delete from the current position to the position resulting from n move-cmds; move-cmd is a movement command (see above) ord, in which case the current line is deleted.[n]rcโ replace the next n characters with the character c.[n]Rโ replace. Enters insert mode but overwrites existing characters instead of inserting before existing characters. The replacement is repeated n times.[n]~โ change the case of the next n characters.[n]ymove-cmdโ yank from the current position to the position resulting from n move-cmds into the yank buffer; if move-cmd isy, the whole line is yanked.Yโ yank from the current position to the end of the line.[n]pโ paste the contents of the yank buffer just after the current position, n times.[n]Pโ same asp, except the buffer is pasted at the current position.
๐ Miscellaneous vi commands
^Jand^Mโ the current line is read, parsed and executed by the shell.^Land^Rโ redraw the current line.[n].โ redo the last edit command n times.uโ undo the last edit command.Uโ undo all changes that have been made to the current line.PC Home,End,Deland cursor keys โ they move as expected, both in insert and command mode.intrandquitโ the interrupt and quit terminal characters cause the current line to be removed to the history and a new prompt to be printed.
โจ FILES โจ
~/.mkshrcโ user mkshrc profile (for non-privileged interactive shells); see "Startup files." The location can be changed at compile time (like, for embedded systems); AOSP Android builds use/system/etc/mkshrc.~/.profileโ user profile (for non-privileged login shells); see "Startup files" near the top of this manual./etc/profileโ system profile (for login shells); see "Startup files."/etc/shellsโ shell database./etc/suid_profileโ privileged shells' profile (sugid); see "Startup files."
Note: on Android, /system/etc/ contains the system and suid profile. ๐ซถ
๐ SEE ALSO ๐
awk(1), cat(1), ed(1), getopt(1), lksh(1), sed(1), sh(1), stty(1), dup(2), execve(2), getgid(2), getuid(2), mknod(2), mkfifo(2), open(2), pipe(2), rename(2), wait(2), getopt(3), nl_langinfo(3), setlocale(3), signal(3), system(3), tty(4), shells(5), environ(7), script(7), utf-8(7), mknod(8)
The FAQ at http://www.mirbsd.org/mksh-faq.htm or in the /usr/share/doc/mksh/FAQ.htm file. ๐
http://www.mirbsd.org/ksh-chan.htm โ go read it, it's giving lore.
Morris Bolsky, The KornShell Command and Programming Language, Prentice Hall PTR, xvi + 356 pages, 1989, ISBN 978-0-13-516972-8 (0-13-516972-0). ๐
Morris I. Bolsky and David G. Korn, The New KornShell Command and Programming Language (2nd Edition), Prentice Hall PTR, xvi + 400 pages, 1995, ISBN 978-0-13-182700-4 (0-13-182700-6).
Stephen G. Kochan and Patrick H. Wood, UNIX Shell Programming, Sams, 3rd Edition, xiii + 437 pages, 2003, ISBN 978-0-672-32490-1 (0-672-32490-3).
IEEE Inc., IEEE Standard for Information Technology โ Portable Operating System Interface (POSIX), IEEE Press, Part 2: Shell and Utilities, xvii + 1195 pages, 1993, ISBN 978-1-55937-255-8 (1-55937-255-9).
Bill Rosenblatt, Learning the Korn Shell, O'Reilly, 360 pages, 1993, ISBN 978-1-56592-054-5 (1-56592-054-6).
Bill Rosenblatt and Arnold Robbins, Learning the Korn Shell, Second Edition, O'Reilly, 432 pages, 2002, ISBN 978-0-596-00195-7 (0-596-00195-9).
Barry Rosenberg, KornShell Programming Tutorial, Addison-Wesley Professional, xxi + 324 pages, 1991, ISBN 978-0-201-56324-5 (0-201-56324-X).
โจ AUTHORS โจ
okay so bestie, the MirBSD Korn Shell was developed by mirabilos (formerly The MirOS Project.) ๐
This shell is built on the public domain 7th edition Bourne shell clone by Charles Forsyth, who very kindly agreed to โ in countries where the Public Domain status of the work may not be valid โ grant a copyright licence to the general public to deal in the work without restriction, plus permission to sublicence derivatives under the terms of any OSI-approved Open Source licence. ๐ซถ And it also includes parts of the BRL shell by Doug A. Gwyn, Doug Kingston, Ron Natalie, Arnold Robbins, Lou Salkind and others.
The first release of pdksh was created by Eric Gisin, and it was subsequently maintained by John R. MacMillan, Simon J. Gerraty and Michael Rendell. The effort by Debian, OpenBSD, and other contributors โ including our users โ to improve the shell is appreciated. ๐ See the documentation, website and the CVS repository (source code) for details.
mksh-os2is developed by KO Myung-Hun<komh@chollian.net>.mksh-w32is developed by Michael Langguth<mail@michael-langguth.de>.mksh/z/OSis contributed by Daniel Richard G.<skunk@iSKUNK.ORG>.
The BSD daemon is Copyright ยฉ Marshall Kirk McKusick. The complete legalese is at: http://www.mirbsd.org/TaC-mksh.txt
๐ CAVEATS ๐
ngl bestie, mksh provides a consistent, clear interface normally. But listen โ this may deviate from POSIX in historic or opinionated places. ๐ set -o posix (see โPOSIX modeโ for details) will make the shell more conformant, but mind the FAQ (see โSEE ALSOโ), especially regarding locales. ๐
mksh (but not lksh) provides a consistent 32-bit integer arithmetic implementation, both signed and unsigned, with sign of the result of a remainder operation and wraparound defined, even (defying POSIX) on 36-bit and 64-bit systems. โจ
mksh currently uses OPTU-16 internally, which is the same as UTF-8 and CESU-8 with 0000..FFFD being valid codepoints; raw octets map to U+EF80..U+EFFF. Future compatibility note: mksh R60 will use full 21-bit UTF-8 and map raw octets to U-001BBB80..U-001BBBFF instead.
๐ BUGS ๐
Suspending (using ^Z) pipelines like the one below will only suspend the currently running part of the pipeline; in this example, โfubarโ is immediately printed on suspension (but not later after an fg). ๐ญ
$ /bin/sleep 666 && echo fubar
The truncation process involved when changing HISTFILE does not free old history entries (leaks memory) and leaks old entries into the new history if their line numbers are not overwritten by same-number entries from the persistent history file; truncating the on-disc file to HISTSIZE lines has always been broken and prone to history file corruption when multiple shells are accessing the file; the rollover process for the in-memory portion of the history is slow, should use memmove(3).
bestie this is the part where you don't @ me about the history behaviour, it's a known thing ๐
This document attempts to describe mksh R59-CURRENT and up, with vendor patches from Debian, compiled without any options impacting functionality, such as MKSH_SMALL, when not called as /bin/sh which, on some systems only, enables set -o posix or set -o sh automatically (whose behaviour differs across targets), for an operating environment supporting all of its advanced needs.
Please report bugs in mksh in the #!/bin/mksh channel, on IRC; note the information at: http://www.mirbsd.org/mksh-faq.htm#contact
okay that's the whole page bestie, you read the entire MKSH(1) manpage and that's iconic of you tbh ๐ this copy is from MirBSD, dated December 23, 2025, so it's fresh fresh โจ go forth and script, mwah ๐
๐
๐ฆ where this page comes from
- ubuntu resolute: mksh 59c-43
- ubuntu stonking: mksh 59c-43
- Copyright ยฉ 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
- Copyright ยฉ 2008, 2009, 2010, 2016, 2018, 2020, 2023, 2025 mirabilos <m$(date +%Y)@mirbsd.de>
- Copyright ยฉ 1991, 1993 The Regents of the University of California. (โป 3-clause BSD)
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms