D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
blackhat.pw
:
/
kunden
/
kunden
/
usr
/
share
/
doc
/
mksh
/
Filename :
FAQ.htm
back
Copy
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <meta name="tdm-reservation" content="1" /> <title>mksh 59c-41+b2 FAQ (local copy)</title> <meta name="source" content="$MirOS: src/bin/mksh/mksh.faq,v 1.45+locale-tracking 2025/04/25 23:14:17 tg Exp $" /> <meta name="generator" content="$MirOS: src/bin/mksh/FAQ2HTML.sh,v 1.10 2025/04/25 23:14:50 tg Exp $" /> <style type="text/css"><!--/*--><![CDATA[/*><!--*/ .boxhead { margin-bottom:0px; } .boxtext { border:4px ridge green; margin:0px 24px 0px 18px; padding:2px 3px 2px 3px; } .boxfoot { margin-top:0px; } h2:before { content:"đ "; } a[href^="ftp://"]:after, a[href^="http://"]:after, a[href^="https://"]:after, a[href^="irc://"]:after, a[href^="mailto:"]:after, a[href^="news:"]:after, a[href^="nntp://"]:after { content:"â"; color:#FF0000; vertical-align:super; margin:0 0 0 1px; } pre { /* â â â â */ margin:0px 9px 0px 15px; } tt { white-space:nowrap; } /*]]>*/--></style> </head><body> <p>Note: Links marked like <a href="irc://irc.mirbsd.org/!/bin/mksh">this one to the mksh IRC channel</a> connect to external resources.</p> <p>â <b>Notice:</b> the website will have <a href="http://www.mirbsd.org/mksh-faq.htm">the latest version of the mksh FAQ</a> online.</p> <h1>Table of Contents</h1> <ul> <li><a href="#spelling">How do you spell <tt>mksh</tt>? How do you pronounce it?</a></li> <li><a href="#sowhatismksh">Iâm a $OS (<i>Android, OS/2, âŠ</i>) user, so whatâs mksh?</a></li> <li><a href="#os2">Iâm an OS/2 user, what else do I need to know?</a></li> <li><a href="#kornshell">How does this relate to ksh or the Korn Shell?</a></li> <li><a href="#packaging">How should I package mksh? (common cases)</a></li> <li><a href="#mkshrc">How does mksh load configuration files?</a></li> <li><a href="#testsuite-fails">The testsuite fails!</a></li> <li><a href="#selinux-androidiocy">I forbid stat(2) in my SELinux policy, and some things do not work!</a></li> <li><a href="#printf-c">Which revision of printf.c do I use?</a></li> <li><a href="#makefile">Why doesnât this use a Makefile to build?</a></li> <li><a href="#oldbsd">Why do other BSDs and QNX still use pdksh instead of mksh?</a></li> <li><a href="#openbsd">Why is there no mksh in OpenBSDâs ports tree?</a></li> <li><a href="#book">Iâd like an introduction.</a></li> <li><a href="#ps1conv">My prompt from <<i>some other shell</i>> does not work!</a></li> <li><a href="#ps1weird">My prompt is weird!</a></li> <li><a href="#aliasify">How do I write an alias?</a></li> <li><a href="#env">On startup files and <tt>$ENV</tt> across and detecting various shells</a></li> <li><a href="#ctrl-x-e">Multiline command editing</a></li> <li><a href="#escaping">Some characters donât display right</a></li> <li><a href="#carets">Whatâs with these ^Q, ^!Q and ^+Q (e.g. from tab completion)? \x80 too!</a></li> <li><a href="#ctrl-l-cls">^L (Ctrl-L) does not clear the screen</a></li> <li><a href="#ctrl-u-pico">^U (Ctrl-U) clears the entire line</a></li> <li><a href="#ctrl-w-bash">^W (Ctrl-W) deletes a word, not a bigword</a></li> <li><a href="#esc-d-whole-word">I want Esc+d to delete the entire word, not just to the right from the cursor</a></li> <li><a href="#cur-up-zsh">Cursor Up behaves differently from zsh</a></li> <li><a href="#amend-git-branch">Display the current git branch in the prompt</a></li> <li><a href="#current">Can mksh set the title of the window according to the command running?</a></li> <li><a href="#other-tty">How do I start mksh on a specific terminal?</a></li> <li><a href="#completion">What about programmable tab completion?</a></li> <li><a href="#posix-mode">How POSIX compliant is mksh? Also, UTF-8 vs. locales?</a></li> <li><a href="#function-local-scopes">What differences in function-local scopes are there?</a></li> <li><a href="#regex-comparison">I get an error in this regex comparison</a></li> <li><a href="#cfor">How can I do C-style âforâ loops?</a></li> <li><a href="#local-arrays">How can I do local arrays?</a></li> <li><a href="#trim-vector">${@?}: bad substitution</a></li> <li><a href="#lineno">error line numbers are⊠somewhat close</a></li> <li><a href="#extensions-to-avoid">Are there any extensions to avoid?</a></li> <li><a href="#while-read-pipe">Something is going wrong with my while...read loop</a></li> <li><a href="#command-alias">âcommandâ doesnât expand aliases as in ksh93</a></li> <li><a href="#builtin-cat">Didnât there used to be a cat(1) builtin?</a></li> <li><a href="#builtin-rename">ârenameâ doesnât work as expected!</a></li> <li><a href="#builtin-sleep">Didnât there used to be a sleep(1) builtin?</a></li> <li><a href="#arith-import">Some integer variables are 0?</a></li> <li><a href="#string-concat">â+=â behaves differently from other shells</a></li> <li><a href="#set-e">I use âset -eâ and my code unexpectedly errors out</a></li> <li><a href="#set-eo-pipefail">I use âset -eo pipefailâ and my code unexpectedly errors out</a></li> <li><a href="#faq">My question is not answered here!</a></li> <li><a href="#contact">How do I contact you (to say thanks, for bugreports and questions)?</a></li> </ul> <h1>Frequently Asked Questions</h1> <h2 id="spelling"><a href="#spelling">How do you spell <tt>mksh</tt>? How do you pronounce it?</a></h2> <div><p>This <a href="http://www.mirbsd.org/mksh.htm">shell</a> is spelt either â<tt>mksh</tt>â (with, even at the beginning of a sentence, <a href="https://en.wikipedia.org/wiki/Wikipedia:Manual_of_Style/Capital_letters#Items_that_require_initial_lower_case">an initial lowercase letter</a>; this is important) or âMirBSD Korn Shellâ, possibly with âtheâ.</p> <p>I usually pronounce it as â<span xml:lang="de-DE-1901">em-ka-es-ha</span>â, that is, the letters individually in my native German, emphasis on the first syllable, or say âMirBSD Korn Shellâ, although it is manageable, mostly for Slavic speakers, to actually say âmkshâ as if it were a word âș</p> <p>Oh⊠Iâve run into this one, didnât I? âMirBSDâ is pronounced â<span xml:lang="de-DE-1901">Mir-Be-Es-De</span>â germanically, for anglophones âMir-beasâtieâ is fine.</p> <p>This translates well into other languages, such as <span xml:lang="es">eme-ka-ese-ache</span> in Spanish, although English speakers may still find âMir-beastie korn shellâ more palatable.</p></div> <h2 id="sowhatismksh"><a href="#sowhatismksh">Iâm a $OS (<i>Android, OS/2, âŠ</i>) user, so whatâs mksh?</a></h2> <div><p>mksh is a so-called (Unix) âshellâ or âcommand interpreterâ, similar to <tt>COMMAND.COM</tt>, <tt>CMD.EXE</tt> or PowerShell on other operating systems you might know. Basically, it runs in a terminal (âconsoleâ or âDOS boxâ) window, taking user input and running that as commands. Itâs also used to write so-called (shell) âscriptâs, short programs made by putting several of those commands into a âbatch fileâ.</p> <p>On Android, mksh is used as the system shellâââbasically, the one running commands at system startup, in the background, and on user behalf (but never of its own). Any privilege pop-ups you might <a href="https://forum.xda-developers.com/showthread.php?t=1963976">be encountering</a> are therefore <a href="https://forum.xda-developers.com/showpost.php?p=33550523&postcount=1553">not caused by mksh</a> but by some other code invoking mksh to do something on its behalf.</p></div> <h2 id="os2"><a href="#os2">Iâm an OS/2 user, what else do I need to know?</a></h2> <div><p>Unlike the native command prompt, the current working directory is, for security reasons common on Unix systems which the shell is designed for, not in the search path at all; if you really need this, run the command <tt>PATH=.$PATHSEP$PATH</tt> or add that to a suitable initialisation file (<tt>~/.mkshrc</tt>).</p> <p>There are two different newline modes for mksh-os2: standard (Unix) mode, in which only LF (0A hex) is supported as line separator, and âtextmodeâ, which also accepts ASCII newlines (CR+LF), like most other tools on OS/2, but creating an incompatibility with standard mksh. If you compiled mksh from source, you will get the standard Unix mode unless <tt>-T</tt> is added during compilation; however, you will most likely have gotten this shell through komhâs port on Hobbes, or from his OS/2 Factory on eComStation Korea, which uses âtextmodeâ, though. Most OS/2 users will want to use âtextmodeâ unless they need absolute compatibility with Unix mksh and other Unix shells and tools.</p></div> <h2 id="kornshell"><a href="#kornshell">How does this relate to ksh or the Korn Shell?</a></h2> <div><p>The Korn Shell (AT&T ksh) was authored by David Korn; two major flavours exist (ksh88 and ksh93), the latter having been maintained until 2012 (last formal release) and 2014 (last beta snapshot, buggy). A ksh86 did exist.</p> <p>The <tt>ksh2020</tt> project to restart development around November 2017 forking the last <tt>ksh93 v-</tt> (beta) snapshot is now dead, but the <tt>ksh93u+m</tt> project from 2021 onwards is active and more stable.</p> <p>AT&T ksh88 is âthe (original) Korn Shellâ. Other implementations, of varying quality (MKS Toolkitâs MKS ksh being named as an example of the lower end, MirBSDâs mksh at the upper end). They are all <em>not</em> âKorn Shellâ or âkshâ. However, mksh got blessed by David Korn, as long as it cannot be confused with the original Korn Shell.</p> <p>The POSIX shell standard, while lacking most Korn Shell features, was largely based on AT&T ksh88, with some from the Bourne shell.</p> <p>mksh is the currently active development of what started as the Public Domain Bourne Shell in the mid-1980s with ksh88-compatibl-ish extensions having been added later, making the Public Domain Korn Shell (pdksh), which, while never officially blessed, was the only way for most to get a Korn Shell-like command interpreter for AT&Tâs was proprietary, closed-source code for a very long time. pdkshâs development ended in 1999, with some projects like Debian and NetBSDÂź creating small bug fixes (which often introduced new bugs) as part of maintenance. Around 2003, OpenBSD started cleaning up their shipped version of pdksh, removing old and compatibility code and modernising it. In 2002, development of what is now mksh started as the system shell of MirBSD, which took over almost all of OpenBSDâs cleanup, adding compatibility to other operating systems back on top of it, and after 2004, independent, massive development of bugfixes including a complete reorganisation of the way the parser works, and of new features both independent and compatible with other shells (ksh93, GNU bash, zsh, BSD csh) started and was followed by working with the group behind POSIX to fix issues both in the standard and in mksh. mksh became the system shell in several other operating systems and Linux distributions and Android and thus is likely the Korn shell, if not Unix shell, flavour with the largest user base. It has replaced pdksh in all contemporary systems except QNX, NetBSDÂź and OpenBSD (who continue to maintain their variant on âlow flameâ).</p> <p>dtksh is the âDesktop Korn Shellâ, a build of AT&T ksh93 with some additional built-in utilities for graphics programming (windows, menu bars, dialogue boxes, etc.) utilising Motif bindings.</p> <p>MKS ksh is a proprietary reimplemention aiming for, but not quite getting close to, ksh88 compatibility.</p> <p>SKsh is an AmigaOS-specific Korn Shell-lookalike by Steve Koren.</p> <p>The <a href="http://www.mirbsd.org/ksh-chan.htm">Homepage of the <tt>#ksh</tt> channel on IRC</a> contains more information about the Korn Shell in general and its flavours.</p></div> <h2 id="packaging"><a href="#packaging">How should I package mksh? (common cases)</a></h2> <div><p>Export a few environment variables, namely <tt>CC</tt> (the C compiler), <tt>CPPFLAGS</tt> (all C prĂŠprocessor definitions), <tt>CFLAGS</tt> (only compiler flags, <em>no</em> <tt>-Dfoo</tt> or anything!), <tt>LDFLAGS</tt> (for anything to pass to the C compiler while linking) and <tt>LIBS</tt> (appended to the linking command line after everything else. You might wish to <tt>export LDSTATIC=-static</tt> for a static build as well.</p> <p>When cross-compiling, <tt>CC</tt> is the <em>cross</em> compiler (mksh currently does not require a compiler targetting the build system), but you <em>must</em> also export <tt>TARGET_OS</tt> to whatever system you are compiling for, e.g. âLinuxâ. For most operating systems, thatâs just the uname(1) output. Some very rare systems also need <tt>TARGET_OSREV</tt>; consult the source code of <tt>Build.sh</tt> for details.</p> <p>Create two subdirectories, say <tt>build-mksh</tt> and <tt>build-lksh</tt>. In each of them, start a compilation by issuing <tt>sh ../Build.sh -r</tt> followed by running the testsuite<a href="#packaging-fn1">Âč</a> via <tt>./test.sh</tt>. For lksh(1) add <tt>-DMKSH_BINSHPOSIX</tt> to <tt>CPPFLAGS</tt> and use <tt>sh ../Build.sh -r -L</tt> to compile.</p> <p>See <a href="#testsuite-fails">below</a> if the testsuite fails.</p> <p>Install <tt>build-mksh/mksh</tt> as <tt>/bin/mksh</tt> (or similar), <tt>build-lksh/lksh</tt> as <tt>/bin/lksh</tt> with a symlink(7) to it from <tt>/bin/sh</tt> (if desred), and <tt>mksh.1</tt> and <tt>lksh.1</tt> as manpages (mdoc macropackage required). Install <tt>dot.mkshrc</tt> either as <tt>/etc/skel/.mkshrc</tt> (meaning your users will have to manually resynchronise their home directoriesâ copies after every package upgrade) or as <tt>/etc/mkshrc</tt>, in which case you install a <a href="https://evolvis.org/plugins/scmgit/cgi-bin/gitweb.cgi?p=alioth/mksh.git;a=blob;f=debian/.mkshrc;hb=HEAD">redirection script like Debianâs</a> into <tt>/etc/skel/.mkshrc</tt>. You may need a <a href="http://www.mirbsd.org/TaC-mksh.txt">summary of the licence information</a>.</p> <p>At runtime, the presence of <tt>/bin/ed</tt> as default history editor is recommended, as well as a manpage formatter; you can also install preformatted manpages from <tt>build-*ksh/*ksh.cat1</tt> if nroff(1) (or <tt>$NROFF</tt>) is available at build time by removing the <tt>-r</tt> flag from either <tt>Build.sh</tt> invocation.</p> <p>Some shell features require the ability to create temporary files and FIFOS (cf. mkfifo(2))/pipes at runtime. Set <tt>TMPDIR</tt> to a suitable location if <tt>/tmp</tt> isnât it; if this is known ahead of time, you can add <tt>-DMKSH_DEFAULT_TMPDIR=\"/path/to/tmp\"</tt> to CPPFLAGS. We currently are unable to determine one on Android because its bionic libc does not expose any method suitable to do so in the generic case.</p> <p id="packaging-fn1">â To run the testsuite, ed(1) must be available as <tt>/bin/ed</tt>, and perl(1) is needed. When cross-compiling, the version of the first <tt>ed</tt> binary on the <tt>PATH</tt> <em>must</em> be the same as that in the target system on which the tests are to be run, in order to be able to detect which flavour of ed to adjust the tests for. Busybox ed is broken beyond repair, and all three ed-related tests will always fail with it.</p></div> <h2 id="mkshrc"><a href="#mkshrc">How does mksh load configuration files?</a></h2> <div><p>The shell loads first <tt>/etc/profile</tt> then <tt>~/.profile</tt> if called as login shell or with the <tt>-l</tt> flag, then loads the file <tt>$ENV</tt> points to (defaulting to <tt>~/.mkshrc</tt>) for interactive shells (that includes login shells).</p> <p>Distributors should take care to either install the <tt>dot.mkshrc</tt> example provided into <tt>/etc/skel/.mkshrc</tt> (so that itâs available for newly created user accounts) and ensure it can propagate to existing accounts or, if upgrading these is difficult, install the shipped file as, for example, <tt>/etc/mkshrc</tt> and install a skeleton file, such as the one in Debian, that sources the file in <tt>/etc</tt>.</p> <p>Itâs vital that users can change the configuration, so do not force a root-provided config file onto them; the shipped file, after all, is just an example.</p> <p>If you need central user and configuration management and cannot use something that installs skeleton files upon home directory creation (like pam_mkhomedir), you can <tt>export ENV</tt> in <tt>/etc/profile</tt> to a file (say <tt>/etc/shellrc</tt>) that sources the per-shell file. Users can, this way, still override it by setting a different <tt>$ENV</tt> in their <tt>~/.profile</tt>.</p></div> <h2 id="testsuite-fails"><a href="#testsuite-fails">The testsuite fails!</a></h2> <div><p>The mksh testsuite has uncovered numerous bugs in operating systems (kernels, libraries), compilers and toolchains. It is likely that you just ran into one. If youâre using LTO (the <tt>Build.sh</tt> option <tt>-c lto</tt>) try to disable it firstâââespecially GCC is a repeat offender breaking LTO and its antecessor <tt>-fwhole-program --combine</tt> and tends to do wrong code generation quite a bit. Otherwise, try lowering the optimisation levels, bisecting, etc.</p></div> <h2 id="selinux-androidiocy"><a href="#selinux-androidiocy">I forbid stat(2) in my SELinux policy, and some things do not work!</a></h2> <div>Donât break Unix. Read up on the GIGO principle. Duh.</div> <h2 id="printf-c"><a href="#printf-c">Which revision of printf.c do I use?</a></h2> <div><p>If you have to add printf(1) as an extra, nĆn-standard, builtin, use <tt>src/usr.bin/printf/printf.c,v</tt> revisionâŠ</p> <ul> <li>r1.25 or newer for mksh CVS HEAD (R59d/R60+)</li> <li>r1.22 for mksh R59c</li> </ul> <p>âŠÂ and add <tt>USE_PRINTF_BUILTIN=1</tt> to the <tt>Build.sh</tt> environment. Do note that this can no longer be used as âspeed hackâ because as of R51, if an external printf(1) exists, it is preferred, as the OSâ own implementations will often have extensions, and they usually will have floating point support (which the one embedded in mksh cannot provide). It mostly exists for invocations where no such utility is in <tt>$PATH</tt> but scripts are targetting POSIX.</p></div> <h2 id="makefile"><a href="#makefile">Why doesnât this use a Makefile to build?</a></h2> <div><p>Not all supported target operating environments have a make utility available, and shell was required for âmirtoconfâ (like autoconf) already anyway, so it was chosen to run the make part as well.</p> <p>You can, however, add the <tt>-M</tt> flag to your <tt>Build.sh</tt> invocations to let it produce a <tt>Makefrag.inc</tt> file <em>tailored for this specific build</em> which you can then include in a Makefile, such as with the BSD make(1) â.includeâ command or <a href="https://www.gnu.org/software/make/manual/make.html#Include">GNU make</a> equivalent. It even contains, for the user to start out with, a commented-out example of how to do that in the most basic manner.</p></div> <h2 id="oldbsd"><a href="#oldbsd">Why do other BSDs and QNX still use pdksh instead of mksh?</a></h2> <div><p>Some systems are resistant to change, mostly due to bikeshedding (some people would, for example, rather see all shells banned to ports/pkgsrcÂź) and hysterial raisins (historical reasons â»). Most BSDs have mksh packages available, and it works on all of them and QNX just fine.</p> <p>In fact, on all of these systems, you can replace their 1999-era <tt>/bin/ksh</tt> (which is a pdksh) with mksh. On at least NetBSDÂź 1.6 and up (not 1.5) and OpenBSD, even <tt>/bin/sh</tt> is fair game.</p> <p>MidnightBSD notably has adopted mksh as system shell (thanks laffer1).</p></div> <h2 id="openbsd"><a href="#openbsd">Why is there no mksh in OpenBSDâs ports tree?</a></h2> <div>OpenBSD donât like people who fork off their project at all; heck, they donât even like the people they themselves forked off (NetBSDÂź). Several people tried over the years to get one committed, but nobody dared so as to not lose their commit bit. If you try, succeed, and survive Theo, however, kudos to you! See also <a href="#oldbsd">the âother BSDsâ FAQ entry</a>.</div> <h2 id="book"><a href="#book">Iâd like an introduction.</a></h2> <div>Unfortunately, nobody has written a book about mksh yet, although other shells have received (sometimes decent) attention from authors and publishers. This FAQ lists a subset of things packagers and generic people ask, and the mksh(1) manpage is more of a reference, so you are probably best off starting with a shell-agnostic, POSIX or ksh88 reference such as the first edition (the second one deals with ksh93 which differs far more from mksh than ksh88, as ancient as it is, does) of the OâReilly book (â disclaimer: only an example, not a recommendation) âLearning the Korn Shellâ and going forward by reading scripts (the â<a href="https://evolvis.org/plugins/scmgit/cgi-bin/gitweb.cgi?p=shellsnippets/shellsnippets.git;a=tree" >shellsnippets</a>â repository, also referenced in <a href="http://www.mirbsd.org/ksh-chan.htm">the <tt>#ksh</tt> IRC channel homepage</a>, has many examples) and trying to understand them and the mksh specifics from the manpage.</div> <h2 id="ps1conv"><a href="#ps1conv">My prompt from <<i>some other shell</i>> does not work!</a></h2> <div><a href="#contact">Contact</a> us by eMail, Fediverse or on IRC, weâll convert it for you. Also have a look at the PS1 section in the mksh(1) manpage (search for âotherwise unused charâ, e.g. with <tt>/</tt> in less(1), to spot it quickly).</div> <h2 id="ps1weird"><a href="#ps1weird">My prompt is weird!</a></h2> <div><p>There are several reasons why your <tt>PS1</tt> might be not what youâd expect:</p><ul> <li><tt>$PS1</tt> is <tt>export</tt>ed. <strong>Do not export PS1!</strong> (This was agreed upon as suggestion in a discussion between bash, zsh and Korn shell developers.) The feature set of different shells vastly differs and each shell should use its default PS1 or from its startup files.</li> <li><tt>$ENV</tt> <a href="#env">is set and probably <tt>export</tt>ed</a>.</li> <li>Your prompt is just â<tt># </tt>â: youâre entering a root shell, and <tt>$PS1</tt> does not contain the â#â character, in which case the shell forces this prompt, making extra privileges obvious.</li> <li>Your prompt is just â<tt>$ </tt>â: perhaps your system administrator did not install the shipped <tt>dot.mkshrc</tt> file, or you did not copy <tt>/etc/skel/.mkshrc</tt> into your home directory (perhaps it was created before <tt>mksh</tt> was installed?). Without another idea for a fix, get <a href="http://www.mirbsd.org/cvs.cgi/~checkout~/src/bin/mksh/dot.mkshrc?rev=HEAD;content-type=text%2Fplain">this file</a> and store it as <tt>~/.mkshrc</tt> then run <tt>mksh</tt>; this will at the very least install our sample (âuser@host:path $ â) prompt.</li> <li>Your prompt contains things like â\uâ or â\wâ: it is for another shell and <a href="#ps1conv">needs converting</a>.</li> <li>Your prompt contains colours, and when the command line is long the cursor position or screen contents, especially using the history, is off: terminal escapes must be escaped from the shell; check the PS1 section in the manpage: search for âotherwise unused charâ (see above).</li> <li>If the prompt doesnât leave enough space on the right, the shell inserts a line break after it when rendering.</li> </ul></div> <h2 id="aliasify"><a href="#aliasify">How do I write an alias?</a></h2> <div><p class="boxhead">Define the following function:</p><div class="boxtext"> <pre> <span style="display:none;"> </span>function aliasify { <span style="display:none;"> </span> local x=$(fc -ln -1) <span style="display:none;"> </span> x=${x#$'\t'} <span style="display:none;"> </span> print -r -- "alias ${1@Q}=${x@Q}" <span style="display:none;"> </span>} </pre> </div><p class="boxfoot">Then type the command you want to aliasify, and then <tt>aliasify <i>foo</i></tt>, where <i>foo</i> is what name you want to give to the alias. Add the result to <tt>~/.mkshrc</tt> or so.</p></div> <h2 id="env"><a href="#env">On startup files and <tt>$ENV</tt> across and detecting various shells</a></h2> <div><p>Interactive shells look at <tt>~/.mkshrc</tt> (or <tt>/system/etc/mkshrc</tt> on Android and <tt>/etc/mkshrc</tt> on FreeWRT and OpenWrt) by default. This location can, however, be overridden by setting the <tt>ENV</tt> environment variable. (FreeBSD is rumoured to set it in their system profile.) Itâs better to not set <tt>$ENV</tt> if possible and let every shell user their native startup files; otherwise, you must ensure that it runs under all shells. Check <tt>$BASH_VERSION</tt> (GNU bash), <tt>$KSH_VERSION</tt> (contains âLEGACY KSHâ or âMIRBSD KSHâ for mksh, âPD KSHâ for ancient mirbsdksh/oksh/pdksh, âVersionâ for ksh93); <tt>$NETBSD_SHELL</tt> (NetBSD ash); <tt>POSH_VERSION</tt> (posh, a pdksh derivative); <tt>$SH_VERSION</tt> (âPD KSHâ as sh), <tt>$YASH_VERSION</tt> (yash), <tt>$ZSH_VERSION</tt> (or if <tt>$VERSION</tt> begins with âzshâ); a <a href="http://www.mirbsd.org/ksh-chan.htm#which-shell">list of more approaches</a> exists.</p> <p>Note that, in some scenarios, it might be very useful to actually set <tt>$ENV</tt>: the regular interactive shell startup file lies in the userâs home directory, relying on being copied from <tt>/etc/skel/</tt> which normally is only done at user creation time. If mksh was installed later, the user often wonât get it at all, and delivering updates is challenging. One way of partially working around this is to ship an <tt>/etc/skel/.mkshrc</tt> that reads <tt>/etc/mkshrc</tt> by default (but the user can change it of course) and ship the <tt>dot.mkshrc</tt> file as <tt>/etc/mkshrc</tt>, but that wonât fully help. This is where <tt>$ENV</tt> comes into play:</p><ul> <li>In <tt>/etc/profile</tt>, set <tt>ENV</tt> to a, say, <tt>shrc</tt> file shipped in <tt>/etc/</tt> and export it.</li> <li>In that new file, which must use only constructs compatible with all shells, usually a subset of POSIX, read the various rc files (<tt>.mkshrc</tt> for mksh, <tt>.kshrc</tt> for AT&T ksh93, etc.) from the userâs home if they exist, from <tt>/etc/skel/</tt> otherwise.</li> </ul><p>This may very well be <em>required</em> if the alternative would be <a href="#ps1weird">to <del><tt>export PS1</tt></del>[sic!]</a>. <a href="https://gitlab.alpinelinux.org/alpine/aports/-/issues/12398#note_146574" >alpine Linux</a> encountered this very problem, and the linked post is a (draft) solution using the <tt>$ENV</tt> method and looks at various other shellsâ startup file situation as well.</p></div> <h2 id="ctrl-x-e"><a href="#ctrl-x-e">Multiline command editing</a></h2> <div><p>mksh is very independent of the terminal and external libraries and databases, such as termcap, and therefore is conservative in which ANSI control codes are sent to the terminal.</p> <p>For this reason, mkshâs input line editing uses a âwindowed one-lineâ concept: the line the cursor is on is a âwindowâ into the whole input, horizontally scrolled. Some other shells (that are much larger and have more dependencies on external tooling) use a âmulti-lineâ editing mode, and users occasionally wish for this. It is on the long-term TODO, but (due to the aforementioned implications) this is not trivial.</p> <p>One way to achieve multi-line editing is to <em>dis</em>able input line editing: <tt>set +o emacs +o vi</tt><br />This will, however, lose you all editing features: tab completion, cursor keys, history, etc.</p> <p>Another way, if you donât need it all the time, is to use a function that spawns your editor on the input line: press <tt>^Xe</tt> in the default emacs mode or <tt>Esc + v</tt> in vi mode. Once you exit the editor, whatever was written there is run; this includes the original command line if you quit without saving, so request the editor to exit nĆn-zero (e.g. using juppâs âabendjoeâ command) to prevent execution. This is <em>really</em> useful to write ad-hĆc scripts as well.</p></div> <h2 id="escaping"><a href="#escaping">Some characters donât display right</a></h2> <div><p>First, make sure that either youâre using a UTF-8 terminal and system and the shellâs UTF-8 mode is on (<tt>set -U</tt>) or that youâre using an 8-bit codepage/CCSID and the UTF-8 mode is off (<tt>set +U</tt>). If youâre on an EBCDIC system ensure to pick a codepage that has a bijective mapping to (Extended) ASCII and in which all necessary characters are present, for example 1047. Furthermore ensure the compile-time and runtime codepages match. (Other encoding schemes, e.g. DBCS or ISO-2022-JP, are not supported.) This should already fix most relevant issues.</p> <p>If using an 8-bit coding system that (unlike e.g. ISO 8859 or EBCDIC) does not assign control characters to âExtended ASCIIâ codepoints 0x80â„0x9F, such as codepages 437, 850, 1252, ⊠(usually on OS/2 or DOS-based systems), enable the option <tt>set -o asis</tt> (new in R60); otherwise, they will be escaped to avoid accidentally setting off terminal control sequences.</p> <p>Note that escaping of characters is, at runtime, dependent on whether the shell was compiled for EBCDIC and/or <tt>utf8-mode</tt> and/or <tt>asis</tt> are enabled, the latter being ignored if either of the former two are true (in UTF-8 mode, UCS C1 codepoints are always escaped).</p></div> <h2 id="carets"><a href="#carets">Whatâs with these ^Q, ^!Q and ^+Q (e.g. from tab completion)? \x80 too!</a></h2> <div>The extended caret notation escapes characters that can be harmful for your terminal from being output as active control characters. This is dependent on the shell mode (see <a href="#escaping">above</a>. The caret (<tt>^</tt>) means Ctrl; <tt>^+</tt> is used to denote UTF-8 C1 control characters, while raw 8-bit C1 control characters use <tt>^!</tt>, and invalid UTF-8 sequences show up as <tt>\x</tt> in <tt>utf8-mode</tt>. The manpage also documents these (search for âcaretâ). Note that the <tt>bind</tt> utility and explicit parameter escaping also quote carets and backslashes with a backslash, while mere output (tab completion, input line editing) donât.</div> <h2 id="ctrl-l-cls"><a href="#ctrl-l-cls">^L (Ctrl-L) does not clear the screen</a></h2> <div>Use ^[^L (Escape+Ctrl-L) or rebind it:<br /> <tt>bind '^L=clear-screen'</tt></div> <h2 id="ctrl-u-pico"><a href="#ctrl-u-pico">^U (Ctrl-U) clears the entire line</a></h2> <div>If you want it to only delete the line up to the cursor, use:<br /> <tt>bind -m ^U='^[0^K'</tt></div> <h2 id="ctrl-w-bash"><a href="#ctrl-w-bash">^W (Ctrl-W) deletes a word, not a bigword</a></h2> <div>If you want it to delete more, with R59d+ you can use:<br /> <tt>bind '^W=delete-bigword-backward'</tt></div> <h2 id="esc-d-whole-word"><a href="#esc-d-whole-word">I want Esc+d to delete the entire word, not just to the right from the cursor</a></h2> <div><p class="boxhead">This is not possible with a simple editing command; however, you can use a macro definition to create a matching effect. First, you need to bind the current definition of Esc+d, i.e. <tt>delete-word-forward</tt>, to something else; Esc+Ctrl-D is currently unused, so weâll use that. Then youâll define a macro that inserts two letters and moves one back (to work at the beginning and end of words safely), then run both delete word backward and forward:</p> <div class="boxtext"> <pre> <span style="display:none;"> </span>bind '^[^D=delete-word-forward' <span style="display:none;"> </span>bind -m '^[d=aa^B^[^H^[^D' </pre> </div><p class="boxfoot">If your shell is sufficiently recent to do so and you want to delete by <a href="#ctrl-w-bash">bigwords</a>, you do not need the first redefinition and simply swap the deletion commands:<br /><tt>bind -m '^[d=aa^B^[H^[D'</tt></p></div> <h2 id="cur-up-zsh"><a href="#cur-up-zsh">Cursor Up behaves differently from zsh</a></h2> <div>Some shells make Cursor Up search in the history only for commands starting with what was already entered. mksh separates the shortcuts: Cursor Up goes up one command and PgUp searches the history as described above. You can, of course, rebind:<br /> <tt>bind '^XA=search-history-up'</tt></div> <h2 id="amend-git-branch"><a href="#amend-git-branch">Display the current git branch in the prompt</a></h2> <div><p style="font-size:small;">Originally posted as wlog entry and for PlĂ€net Debian and PlĂ€net Commanline on 2012-07-14T22:17:01Z</p> <p class="boxhead">Originally <a href="http://web.archive.org/web/20161008060953/http://www.perrier.eu.org/weblog/2012/07/15#cool-prompt">posted by bubulle</a> on Planet Debian, a shell prompt that displays the current git branch, in colour on some terminals, after the current working directory. The following snippet does similar things for <a href="http://www.mirbsd.org/mksh.htm">mksh</a> users, except it doesnât redefine your prompt but amend itâââjust throw it at the bottom of your <tt>~/.mkshrc</tt> before that last line beginning with a colon (copy from <a href="https://evolvis.org/plugins/scmgit/cgi-bin/gitweb.cgi?p=alioth/mksh.git;a=blob;f=debian/.mkshrc;hb=HEAD"><tt>/etc/skel/.mkshrc</tt></a> if you havenât done that yet):</p><div class="boxtext"> <pre> <span style="display:none;"> </span>function parse_git_branch { <span style="display:none;"> </span> git branch 2>/dev/null | sed -n '/^\* \(.*\)/s//(\1)/p' <span style="display:none;"> </span>} <span style="display:none;"> </span>function amend_prompt_with_git { <span style="display:none;"> </span> [[ -o utf8-mode ]]; local u=$? <span style="display:none;"> </span> set +U <span style="display:none;"> </span> local p q='$(parse_git_branch)' r <span style="display:none;"> </span> if [[ $TERM = @(xterm-color|xterm|screen*) ]]; then <span style="display:none;"> </span> if [[ ${PS1:1:1} = $'\r' ]]; then <span style="display:none;"> </span> p=${PS1:0:1} <span style="display:none;"> </span> else <span style="display:none;"> </span> p=$'\001' <span style="display:none;"> </span> PS1=$p$'\r'$PS1 <span style="display:none;"> </span> fi <span style="display:none;"> </span> q=$p$'\e[1;33m'$p$q$p$'\e[0m'$p <span style="display:none;"> </span> fi <span style="display:none;"> </span> p=${PS1%%*( )[#$]*( )} <span style="display:none;"> </span> if [[ $p != "$PS1" ]]; then <span style="display:none;"> </span> # prompt ends with space + #-or-$ + space, we can amend <span style="display:none;"> </span> r=${PS1: ${#p}} <span style="display:none;"> </span> PS1=$p$q$r <span style="display:none;"> </span> fi <span style="display:none;"> </span> (( u )) || set -U <span style="display:none;"> </span>} <span style="display:none;"> </span>amend_prompt_with_git <span style="display:none;"> </span>unset -f amend_prompt_with_git </pre> </div><p class="boxfoot">The indirection by use of a function is not strictly necessary but allows the use of locals. I took the liberty of adding an asterisk after âscreenâ to match the GNU/Linux nonsense of having <tt>TERM=screen.xterm</tt> or somesuch.</p> <p>The insertion point is right before the trailing space plus (either dollar or number sign) plus space, i.e. after the cwd from the default prompt. YMMV so you may need to customise that, or ask me to help.</p></div> <h2 id="current"><a href="#current">Can mksh set the title of the window according to the command running?</a></h2> <div>Thereâs no such thing as âthe command currently runningâ; consider pipelines and delays (<tt>cmd1 | (cmd2; sleep 3; cmd3) | cmd4</tt>). There is, however, a way to make the shell display the command <em>line</em> during the time it is executed; for testing, you will need to download <a href="https://evolvis.org/plugins/scmgit/cgi-bin/gitweb.cgi?p=shellsnippets/shellsnippets.git;a=blob;f=mksh/terminal-title;hb=HEAD">this script</a> and <tt>source</tt> it. For merging into your <tt>~/.mkshrc</tt> you should first understand how it works: lines 4â18 set a <tt>PS1</tt> (prompt) equivalent to lines 84â96 of the stock <tt>dot.mkshrc</tt>, with one change: line 15 (<tt>print >/dev/tty âŠ</tt>) is new, inserted just before the <tt>return</tt> command of the function substitution in the default prompt; this is what youâll need to merge into your own, custom, prompt (if you have one; otherwise pull this adaption to the default one). Line 19 is the only other thing in this script rebinding the Ctrl-M key (which is normally produced by the Enter/Return key) to code that⊠does <em>something crazy</em>. This trick however <em>does funny things with multiline commands</em>, so if you type something out in multiple lines, for example <strong>here documents</strong> or <strong>loops</strong> press <strong>Ctrl-J instead of Enter/Return</strong> after <em>each</em> line including the first (at PS1) and final (at PS2) one.</div> <h2 id="other-tty"><a href="#other-tty">How do I start mksh on a specific terminal?</a></h2> <div><p>Normally: <tt>mksh -T<i>/dev/tty2</i></tt></p> <p>However, if you want for it to return (e.g. for an embedded system rescue shell), use this on your real console device instead: <tt>mksh -T!<i>/dev/ttyACM0</i></tt></p> <p>mksh can also daemonise (send to the background): <tt>mksh -T- -c 'exec cdio lock'</tt></p></div> <h2 id="completion"><a href="#completion">What about programmable tab completion?</a></h2> <div>The shell itself provides static deterministic tab completion. However, you can use hooks like reprogramming the Tab key to a command line editor macro, and using the <tt>evaluate-region</tt> editor command together with <tt>quote-region</tt> and shell functions to implement a programmable completion engine. Multiple people have been considering doing so in our IRC channel; weâll hyperlink to these engines when they are available.</div> <h2 id="posix-mode"><a href="#posix-mode">How POSIX compliant is mksh? Also, UTF-8 vs. locales?</a></h2> <div><p>Youâll need to use the <tt>lksh</tt> binary, unless your C <tt>long</tt> type is 32 bits wide, for POSIX-compliant arithmetic in the shell. This is because <tt>mksh</tt> provides consistent, wraparound-defined, 32-bit arithmetics on all platforms normally. Youâll also need to enable POSIX mode (<tt>set -o posix</tt>) explicitly, which also disables brace expansion upon being enabled (use <tt>set -o braceexpand</tt> to reenable if needed).</p> <p>For the purpose of POSIX, mksh supports only the <tt>C</tt> locale. mkshâs <tt>utf8-mode</tt> <em>must</em> stay disabled in POSIX mode (it was disabled upon enabling POSIX mode in R56â„R59c but decoupled again with R59d).</p> <p>EBCDIC interacts with <tt>utf8-mode</tt> in a special way: UTF-EBCDIC is not used by anyone, we cannot use UCS-2/4 in the shell, so ânega-UTF-8â, a scheme in which UTF-8 calculations are done on the octets converted per the current EBCDIC codepage to âextended ASCIIâ.</p> <p>The shellâs <tt>utf8-mode</tt> <em>before</em> mksh R60 supported only the BMP (Basic Multilingual Plane) of UCS and mapped raw (extended ASCII) octets, i.e. these which are not valid UTF-8 BMP codepoints) into the U+EF80â„U+EFFF range, which is allocated at the CSUR for this purpose. (It otherwise lies in the PUA; however, there is ambiguity if encountering those UTF-8-encoded, so it changed for R60.) The <tt>Arithmetic expressions</tt> and <tt>CAVEATS</tt> sections in mksh(1) contain more details about encoding and mapping.</p> <p>As of R60, <tt>utf8-mode</tt> maps âraw octetsâ to U-001BBB80â„U-001BBBFF, which is outside the UCS and therefore collision-free, using full 21-bit UTF-8 (without explicit CESU-8 compatibility).</p> <p class="boxhead">The following POSIX sh-compatible code toggles the <tt>utf8-mode</tt> option dependent on the current POSIX locale, for mksh to allow using the UTF-8 mode, within the constraints outlined above, in code portable across various shell implementations:</p> <div class="boxtext"> <pre> <span style="display:none;"> </span>case ${KSH_VERSION:-} in <span style="display:none;"> </span>*MIRBSD\ KSH*|*LEGACY\ KSH*) <span style="display:none;"> </span> case ${LC_ALL:-${LC_CTYPE:-${LANG:-}}} in <span style="display:none;"> </span> *[Uu][Tt][Ff]8*|*[Uu][Tt][Ff]-8*) set -U ;; <span style="display:none;"> </span> *) set +U ;; <span style="display:none;"> </span> esac ;; <span style="display:none;"> </span>esac </pre> </div><p class="boxfoot">This only applies to mksh before R60 without locale tracking and is obsolete as of R60âs release, except for backwards compatibility. <strong>This build of mksh already enables it.</strong></p> <p>The shell is pretty close to POSIX, when run as <tt>lksh -o posix</tt> under the "C" locale it is intended to match. It does not do everything like other POSIX-compatible or âcompliant shells, though.</p> <p>Like pretty much all other POSIX-compatible shells, builtins are <em>independent</em> of paths and always recognised in mksh.</p></div> <h2 id="function-local-scopes"><a href="#function-local-scopes">What differences in function-local scopes are there?</a></h2> <div><p><tt>mksh</tt> has a different scope model from AT&T <tt>ksh</tt>, which leads to subtle differences in semantics for identical builtins. This can cause issues with a <tt>nameref</tt> to suddenly point to a local variable by accident. (Other common shells share mkshâs scoping model.)</p> <p class="boxhead">GNU <tt>bash</tt> allows unsetting local variables; in <tt>mksh</tt>, doing so in a function allows back access to the global variable (actually the one in the next scope up) with the same name. The following code, when run before function definitions, changes the behaviour of <tt>unset</tt> to behave like other shells (the alias can be removed after the definitions):</p> <div class="boxtext"> <pre> <span style="display:none;"> </span>case ${KSH_VERSION:-} in <span style="display:none;"> </span>*MIRBSD KSH*|*LEGACY KSH*) <span style="display:none;"> </span> function unset_compat { <span style="display:none;"> </span> \\builtin typeset unset_compat_x <span style="display:none;"> </span> for unset_compat_x in "$@"; do <span style="display:none;"> </span> eval "\\\\builtin unset $unset_compat_x[*]" <span style="display:none;"> </span> done <span style="display:none;"> </span> } <span style="display:none;"> </span> \\builtin alias unset=unset_compat <span style="display:none;"> </span> ;; <span style="display:none;"> </span>esac </pre> </div><p class="boxfoot">When a local variable is created (e.g. using <tt>local</tt>, <tt>typeset</tt>, <tt>integer</tt> or <tt>\\builtin typeset</tt>) it does not, like in other shells, inherit the value from the global (next scope up) variable with the same name; it is rather created without any value (unset but defined).</p></div> <h2 id="regex-comparison"><a href="#regex-comparison">I get an error in this regex comparison</a></h2> <div><p>Use extglobs instead of regexes:<br /> <tt>[[ foo =~ (foo|bar).*baz ]]</tt><br /> âŠÂ becomesâŠ<br /> <tt>[[ foo = *@(foo|bar)*baz* ]]</tt></p></div> <h2 id="cfor"><a href="#cfor">How can I do C-style âforâ loops?</a></h2> <div><p>The <tt>for</tt> loop in shell is always a âforeachâ loop, not a C-style âforâ loop. However, you <em>can</em> use the <tt>while</tt> loop.</p> <p class="boxhead">The following three constructs are equivalent: the first is using the GNU bashâ and AT&T ksh93 C-style for loop, which the second naĂŻvely transfers into a <tt>while</tt> loop that the third example does natively:</p> <div class="boxtext"> <pre> <span style="display:none;"> </span># expr1 expr2 expr3 <span style="display:none;"> </span>for ((idx = 9; idx > 6; --idx)); do <span style="display:none;"> </span> echo $idx <span style="display:none;"> </span>done <span style="display:none;"> </span>idx=9 <span style="display:none;"> </span>while (( idx > 6 )); do <span style="display:none;"> </span> echo $idx <span style="display:none;"> </span> (( --idx )) <span style="display:none;"> </span>done <span style="display:none;"> </span>idx=10 <span style="display:none;"> </span>while (( --idx > 6 )); do <span style="display:none;"> </span> echo $idx <span style="display:none;"> </span>done </pre> </div><p class="boxfoot">The latter two also run on bash and ksh93, so itâs better to use that anyway.</p> <p>The last (native) example rolls the âexpr3â part, which otherwise is run at the end of every body, into the loop condition (âexpr2â) accounting for the extra first execution by âundoingâ its effect in the âexpr1â initialisation, here by pre-incrementing as the âexpr3â is a decrement.</p> <p class="boxhead">Classic counting loops look like this:</p> <div class="boxtext"> <pre> <span style="display:none;"> </span>i=-1 <span style="display:none;"> </span>while (( ++i < 6 )); do <span style="display:none;"> </span> (( j = i )) <span style="display:none;"> </span> while (( ++j < 6 )); do <span style="display:none;"> </span> print -r -- $i, $j <span style="display:none;"> </span> done <span style="display:none;"> </span>done </pre> </div><p class="boxfoot">Here, the increment is offset by a pre-decrement.</p></div> <h2 id="local-arrays"><a href="#local-arrays">How can I do local arrays?</a></h2> <div><p class="boxhead">mksh supports function-local arrays with an âonion modelâ in which you can basically create (and unset) a local variable in a function, which may of course be array-typed:</p> <div class="boxtext"> <pre> <span style="display:none;"> </span>function foo { <span style="display:none;"> </span> a[1]=x # modifies the outer array <span style="display:none;"> </span> echo ${a[*]} <span style="display:none;"> </span> local a # makes a local variable⊠<span style="display:none;"> </span> set -A a # ⊠of type array⊠<span style="display:none;"> </span> a[0]=yz # modifies the inner array <span style="display:none;"> </span> echo ${a[*]} <span style="display:none;"> </span> unset a # removes the local variable <span style="display:none;"> </span> echo ${a[*]} <span style="display:none;"> </span> a[2]=! # modifies the unveiled outer again <span style="display:none;"> </span> echo ${a[*]} <span style="display:none;"> </span>} <span style="display:none;"> </span>set -A a -- 1 2 3 4 5 <span style="display:none;"> </span>echo ${a[*]} # shows the outer array before⊠<span style="display:none;"> </span>foo <span style="display:none;"> </span>echo ${a[*]} # âŠand after the function ran </pre> </div><p class="boxfoot">This also works with <tt>a=(âŠ)</tt> and in POSIX-style functions <tt>foo() { âŠ; }</tt> (in mksh, although not in AT&T ksh which uses a different scope model) and with appending <tt>a+=(âŠ)</tt> (and <tt>set -A a+ -- âŠ</tt>), and even no-truncation array assignments <tt>set +A a -- âŠ</tt> behave in a consistent manner.</p></div> <h2 id="trim-vector"><a href="#trim-vector">${@?}: bad substitution</a></h2> <div><p>In mksh, you cannot assign to or trim a vector (yet). For most cases it is possible to write the affected code in a way avoiding this extension; for example, trimming <tt>${@#foo}</tt> could be applied to <tt>$1</tt> only and <tt>${@?}</tt> can be replaced with a test whether <tt>$# -eq 0</tt>.</p></div> <h2 id="lineno"><a href="#lineno">error line numbers are⊠somewhat close</a></h2> <div><p>For block constructs (such as <tt>if</tt>) and function calls, the shell currently reports the line number of the call site (the trailing <tt>fi</tt>), not the line with the command where the actual error occurred.</p> <p>While unfortunate, the line numbers are currently only updated when reading commands, not tracked through the internal AST. This is not easy to change and therefore will only be fixed as part of introduction of BASH_SOURCE, FUNCNAME, BASH_LINENO, etc.</p></div> <h2 id="extensions-to-avoid"><a href="#extensions-to-avoid">Are there any extensions to avoid?</a></h2> <div><p>GNU <tt>bash</tt> supports â<tt>&></tt>â (and â<tt>|&</tt>â) to redirect both stdout and stderr in one go, but this breaks POSIX and Korn Shell syntax; use POSIX redirections instead:</p> <table border="1" cellpadding="3"> <tr><td>GNU bash</td><td> <tt>foo |& bar |& baz &>log</tt> </td></tr> <tr><td>POSIX</td><td> <tt>foo 2>&1 | bar 2>&1 | baz >log 2>&1</tt> </td></tr> </table></div> <h2 id="while-read-pipe"><a href="#while-read-pipe">Something is going wrong with my while...read loop</a></h2> <div><p class="boxhead">Most likely, youâve encountered the problem in which the shell runs all parts of a pipeline as subshell. The inner loop will be executed in a subshell and variable changes cannot be propagated if run in a pipeline:</p> <div class="boxtext"> <pre> <span style="display:none;"> </span>bar | baz | while read foo; do ...; done </pre> </div><p class="boxfoot">Note that <tt>exit</tt> in the inner loop will also only exit the subshell and not the original shell. Likewise, if the code is inside a function, <tt>return</tt> in the inner loop will only exit the subshell and wonât terminate the function.</p> <p class="boxhead">Use co-processes instead:</p> <div class="boxtext"> <pre> <span style="display:none;"> </span>bar | baz |& <span style="display:none;"> </span>while read -p foo; do ...; done <span style="display:none;"> </span>exec 3>&p; exec 3>&- </pre> </div><p class="boxfoot">If <tt>read</tt> is run in a way such as <tt>while read foo; do ...; done</tt> then leading whitespace will be removed (IFS) and backslashes processed. You might want to use <tt>while IFS= read -r foo; do ...; done</tt> for pristine I/O.</p> <p class="boxhead">Similarly, when using the <tt>-a</tt> option, use of the <tt>-r</tt> option might be prudent (<tt>read -raN-1 arr <file</tt>); the same applies for NUL-terminated lines:</p> <div class="boxtext"> <pre> <span style="display:none;"> </span>find . -type f -print0 |& \ <span style="display:none;"> </span> while IFS= read -d '' -pr filename; do <span style="display:none;"> </span> print -r -- "found <${filename#./}>" <span style="display:none;"> </span>done </pre> </div></div> <h2 id="command-alias"><a href="#command-alias">âcommandâ doesnât expand aliases as in ksh93</a></h2> <div>This is because AT&T ksh93 ships a predefined alias enabling this:<br /> <tt>alias command='command '</tt><br /> put this into your <tt>~/.mkshrc</tt> (note the space before the closing single quote)</div> <h2 id="builtin-cat"><a href="#builtin-cat">Didnât there used to be a cat(1) builtin?</a></h2> <div><p>Up to and including mksh R59c, we indeed shipped a built-in cat(1) inside mksh; this was added originally because Android did not have one <em>at all</em> (but they have since imported a BSD cat). While it could speed up some sh scripts correct signal handling is hard to get right, so (with regret) it was removed in 2021. đ</p></div> <h2 id="builtin-rename"><a href="#builtin-rename">ârenameâ doesnât work as expected!</a></h2> <div><p>Thereâs a <tt>rename</tt> built-in utility in mksh, which is a very thin wrapper around the rename(2) syscall. It receives two pathnames, source and destination where the first is then atomically renamed to the latter. It does not move, i.e. fails for different filesystems.</p> <p>The builtin may be absent if your OS doesnât have rename(2), e.g. Xenix.</p> <p>The GNU package <tt>util-linux</tt> has a different <tt>rename</tt> command. If you wish to invoke an external utility (in favour over a builtin), you can use <tt>dot.mkshrc</tt>âs function <tt>enable</tt> or put the following into your <tt>~/.mkshrc</tt>:</p> <pre>alias rename="$(whence -p rename)"</pre></div> <h2 id="builtin-sleep"><a href="#builtin-sleep">Didnât there used to be a sleep(1) builtin?</a></h2> <div><p>Up to and including mksh R59c, we indeed shipped a subsecond-capable select(2)-based built-in sleep(1). This got originally added because too many platforms do not support sub-second sleep, which nowadays is of less concern. It also led to users complaining about lack for system *ahem* GNU extensions, but the cause of its demise is that getting signal handling right, in a portable way and without too many syscalls (thereâs a threshold over which fork+exec is cheaper!), isnât feasible if even at all possible.</p> <p>The MirOS Project now ships <a href="http://www.mirbsd.org/subprj.htm#sleep">a portable sleep</a> which similarly is select(2)-based and capable of subsecond sleep but in addition supports all GNU extensions related to specifying the amount of time to sleep. It will work on <em>at least</em> all platforms on which mksh had a builtin before. Please install this if your operating system lacks a good enough sleep(1) utility.</p> <p>Note that, if your OS lacks select(2), youâll lose out either way. In that case, GNU coreutilsâ sleep, which is built on older syscalls, may work if the copyleft licence isnât a showstopper for you.</p></div> <h2 id="arith-import"><a href="#arith-import">Some integer variables are 0?</a></h2> <div><p class="boxhead">To mitigate potential exploits, variables imported from the environment are not trusted in arithmetic context; that isâŠ</p> <div class="boxtext"> <pre> <span style="display:none;"> </span>foo=1+1 mksh -c 'integer foo; print $foo' <span style="display:none;"> </span>foo=1+1 mksh -c 'integer foo=$foo; print $foo' </pre> </div><p class="boxfoot">⊠will lose the value in the first line, while the second line explicitly âuntaintsâ, to use a Perl term, the content. Purely numeric values will pass, though.</p></div> <h2 id="string-concat"><a href="#string-concat">â+=â behaves differently from other shells</a></h2> <div><p>In POSIX shell, â=â in code like <tt>var=content</tt> is a string assignment, always. You can use <tt>var=$((content))</tt> for an arithmetic assignment that mostly uses C language rules.</p> <p>It stands to consider that the common shell extension â+=â as in <tt>var+=content</tt> would always do string concatenation; it does in mksh, but not in some other shells, in which, when <tt>var</tt> has been declared integer, addition is done instead.</p> <p>You can make the code portable by using â((âŠ))â (a.k.a. <tt>let</tt>) instead: <tt>(( var += content ))</tt> does arithmetic addition in all shells involved.</p></div> <h2 id="set-e"><a href="#set-e">I use âset -eâ and my code unexpectedly errors out</a></h2> <div><p>I personally recommend people to not use â<tt>set -e</tt>â, as it makes error handling more difficult. However, some insist. There have been bugfixes (relative to e.g. oksh/loksh and posh) in this aspect, and the user has to make sure <tt>$?</tt> is always 0 ASAP even after a command that doesnât check it.</p> <pre>istwo() { for i in "$@"; do test x"$i" = x"2" && echo two done } set -e istwo 1 echo END</pre> <p>This can be fixed by either adding an explicit â<tt>:</tt>â (or â<tt>true</tt>â) after the comparison, or evenâŠ</p> <pre>test x"$i" = x"2" && echo two || :</pre> <p>⊠or right after the <tt>done</tt> inside the function, butâŠ</p> <pre>test x"$i" != x"2" || echo two</pre> <p>⊠negating the condition and using â<tt>||</tt>â is preferable.</p> <p>Remember that Korn shell-style functions (with <tt>function</tt> keyword and <strong>without</strong> parenthesÄs) in AT&T ksh93 and mksh R51 and up have their own shell option scope, but whileâŠ</p> <pre>function istwo { set +e ⊠}</pre> <p>⊠might help in error handling, the return status of a function is still the last errorlevel inside, so an explicit true (â<tt>:</tt>â) or, more explicitly, â<tt>return 0</tt>â at its end is still needed if the <em>caller</em> runs under <tt>set -e</tt>.</p></div> <h2 id="set-eo-pipefail"><a href="#set-eo-pipefail">I use âset -eo pipefailâ and my code unexpectedly errors out</a></h2> <div><p class="boxhead">Related to the above FAQ entry, using <tt>set -o pipefail</tt> makes the following construct error out:</p> <div class="boxtext"> <pre> <span style="display:none;"> </span>set -e <span style="display:none;"> </span>for x in 1 2; do <span style="display:none;"> </span> false && echo $x <span style="display:none;"> </span>done | cat </pre> </div><p class="boxfoot">This is because, while the <tt>&&</tt> ensures that the inner commandâs failure is not taken, it sets the entire <tt>for</tt>â„<tt>done</tt> loopâs errorlevel, which is passed on by <tt>-o pipefail</tt>.</p> <p>Invert the inner command:<br /> <tt>true || echo $x</tt></p></div> <h2 id="faq"><a href="#faq">My question is not answered here!</a></h2> <div>Do read the mksh(1) and lksh(1) manual pages and the <a href="http://www.mirbsd.org/mksh.htm">homepage</a> and other pages like the <a href="http://www.mirbsd.org/mksh_oe.htm">operating environment-specific notes for mksh</a> overview page. You might also wish to read the <a href="http://www.mirbsd.org/ksh-chan.htm">homepage of the <tt>#ksh</tt> IRC channel</a> which lists several resources for Korn or POSIX-compatible shells in general. Or, <a href="#contact">contact</a> us (developer and users).</div> <h2 id="contact"><a href="#contact">How do I contact you (to say thanks, for bugreports and questions)?</a></h2> <div><p>You can say hi in the <tt>#!/bin/mksh</tt> channel on <a href="http://www.mirbsd.org/irc.htm">IRC</a> (OFTC, for now), where not only the developer but also helpful other people idle around.</p> <p>The <a href="#faq">extra resources</a> from the FAQ entry just one above should also be considered ;-)</p> <p>If you insist on sending a bugreport, IRC, Fedi (AP) and eMail are great places for that; <a href="https://launchpad.net/mksh">Launchpad</a>, an external gratis service provided by a company, can also be used if you like web-based issue trackers better.</p> <p>The primary developer can be reached via Fediverse at <tt>@mirabilos@toot.mirbsd.org</tt> (primary account) or <tt>@mirabilos@ipv6.camp</tt> (backup account).</p></div> <h1>Imprint</h1> <p>This offline HTML page for mksh 59c-41+b2 was automatically generated from the sources.</p> </body></html>