代码拉取完成,页面将自动刷新
RCSID: $MirOS: src/bin/mksh/mksh.faq,v 1.10 2020/10/01 22:59:12 tg Exp $
ToC: spelling
Title: How do you spell <tt>mksh</tt>? How do you pronounce it?
<p>This <a href="@@RELPATH@@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, 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>
----
ToC: sowhatismksh
Title: I’m a $OS (<i>Android, OS/2, …</i>) user, so what’s mksh?
<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>
----
ToC: os2
Title: I’m an OS/2 user, what else do I need to know?
<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>
----
ToC: kornshell
Title: How does this relate to ksh or the Korn Shell?
<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>There’s now <tt>ksh2020</tt>, a project having restarted development
around November 2017 forking the last <tt>ksh93 v-</tt> (beta) snapshot
and continuing to develop it, presented at FOSDEM.</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="@@RELPATH@@ksh-chan.htm">Homepage of the <tt>#ksh</tt>
channel on Freenode IRC</a> contains more information about the Korn
Shell in general and its flavours.</p>
----
ToC: packaging
Title: How should I package mksh? (common cases)
<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="@@RELPATH@@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>
----
ToC: mkshrc
Title: How does mksh load configuration files?
<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>
----
ToC: testsuite-fails
Title: The testsuite fails!
<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>
----
ToC: selinux-androidiocy
Title: I forbid stat(2) in my SELinux policy, and some things do not work!
Don’t break Unix. Read up on the GIGO principle. Duh.
----
ToC: makefile
Title: Why doesn’t this use a Makefile to build?
<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>
----
ToC: oldbsd
Title: Why do other BSDs and QNX still use pdksh instead of mksh?
<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>
----
ToC: openbsd
Title: Why is there no mksh in OpenBSD’s ports tree?
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>.
----
ToC: book
Title: I’d like an introduction.
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) and going forward by reading scripts (the
“shellsnippets” repository referenced in the <tt>#ksh</tt> channel
homepage (see the top of this document) has many examples) and
trying to understand them and the mksh specifics from the manpage.
----
ToC: ps1conv
Title: My prompt from <<i>some other shell</i>> does not work!
<a href="#contact">Contact</a> us on the mailing list 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).
----
ToC: ps1weird
Title: My prompt is weird!
<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/or <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>
----
ToC: env
Title: On startup files and <tt>$ENV</tt> across and detecting various shells
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="@@RELPATH@@ksh-chan.htm#which-shell">list of more approaches</a> exists.
----
ToC: ctrl-x-e
Title: Multiline command editing
<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>
----
ToC: ctrl-l-cls
Title: ^L (Ctrl-L) does not clear the screen
Use ^[^L (Escape+Ctrl-L) or rebind it:<br />
<tt>bind '^L=clear-screen'</tt>
----
ToC: ctrl-u-pico
Title: ^U (Ctrl-U) clears the entire line
If it should only delete the line up to the cursor, use:<br />
<tt>bind -m ^U='^[0^K'</tt>
----
ToC: cur-up-zsh
Title: Cursor Up behaves differently from zsh
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>
----
ToC: current
Title: Can mksh set the title of the window according to the command running?
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.
----
ToC: other-tty
Title: How do I start mksh on a specific terminal?
<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>
----
ToC: completion
Title: What about programmable tab completion?
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 (modulo a bugfix) 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.
----
ToC: posix-mode
Title: How POSIX compliant is mksh? Also, UTF-8 vs. locales?
<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> (which only supports the BMP (Basic Multilingual Plane) of
UCS and maps raw octets into the U+EF80‥U+EFFF wide character range; see
<tt>Arithmetic expressions</tt> in mksh(1) for details) <em>must</em> stay
disabled in POSIX mode (it is disabled upon enabling POSIX mode in R56+).</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>
case ${KSH_VERSION:-} in
*MIRBSD KSH*|*LEGACY KSH*)
case ${LC_ALL:-${LC_CTYPE:-${LANG:-}}} in
*[Uu][Tt][Ff]8*|*[Uu][Tt][Ff]-8*) set -U ;;
*) set +U ;;
esac ;;
esac
</pre>
</div><p class="boxfoot">In near future, (UTF-8) locale tracking will
be implemented, though.</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>
----
ToC: function-local-scopes
Title: What differences in function-local scopes are there?
<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>
case ${KSH_VERSION:-} in
*MIRBSD KSH*|*LEGACY KSH*)
function unset_compat {
\\builtin typeset unset_compat_x
for unset_compat_x in "$@"; do
eval "\\\\builtin unset $unset_compat_x[*]"
done
}
\\builtin alias unset=unset_compat
;;
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>
----
ToC: regex-comparison
Title: I get an error in this regex comparison
<p>Use extglobs instead of regexes:<br />
<tt>[[ foo =~ (foo|bar).*baz ]]</tt><br />
… becomes…<br />
<tt>[[ foo = *@(foo|bar)*baz* ]]</tt></p>
----
ToC: trim-vector
Title: ${@?}: bad substitution
<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>
----
ToC: extensions-to-avoid
Title: Are there any extensions to avoid?
<p>GNU <tt>bash</tt> supports “<tt>&></tt>” (and “|&”) 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>
----
ToC: while-read-pipe
Title: Something is going wrong with my while...read loop
<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>
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>
bar | baz |&
while read -p foo; do ...; done
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>
find . -type f -print0 |& \
while IFS= read -d '' -pr filename; do
print -r -- "found <${filename#./}>"
done
</pre>
</div>
----
ToC: command-alias
Title: “command” doesn’t expand aliases as in ksh93
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)
----
ToC: builtin-rename
Title: “rename” doesn’t work as expected!
<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 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>
----
ToC: builtin-sleep
Title: “sleep” does not accept ‘m’ for minutes!
<p>mksh contains a <tt>sleep</tt> built-in utility, in order to be
able to offer sub-second sleep to shell scripts for most platforms.
(It does not exist if the platform lacks select(2) — which should
be rare.)</p>
<p>GNU coreutils contains a sleep implementation accepting suffixed
numbers. 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 something along the following lines into <tt>~/.mkshrc</tt>:</p>
<pre>alias sleep="$(whence -p sleep)"</pre>
<pre>timer() { sleep $(($1*60${2:++$2})); } # timer mins [secs]</pre>
<pre>timer() {
local arg=${1/m/'*60+'}
[[ $arg = *+ ]] && arg+=0
sleep $(($arg)
}</pre>
----
ToC: string-concat
Title: “+=” behaves differently from other shells
<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>
----
ToC: set-e
Title: I use “set -e” and my code unexpectedly errors out
<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>
----
ToC: set-eo-pipefail
Title: I use “set -eo pipefail” and my code unexpectedly errors out
<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>
set -e
for x in 1 2; do
false && echo $x
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>
----
ToC: faq
Title: My question is not answered here!
Do read the mksh(1) manual page. You might also wish to read the <a
href="@@RELPATH@@ksh-chan.htm">homepage of the <tt>#ksh</tt> IRC channel
on Freenode</a> which lists several resources for Korn or POSIX-compatible
shells in general. Or, <a href="#contact">contact</a> us (developer and
users), for example via IRC.
----
ToC: contact
Title: How do I contact you (to say thanks)?
You can say hi in the <tt>#!/bin/mksh</tt> channel on Freenode <a
href="@@RELPATH@@irc.htm">IRC</a>, although a <a
href="@@RELPATH@@danke.htm">donation</a> wouldn’t be amiss ☺ The <a
href="http://www.mail-archive.com/miros-mksh@mirbsd.org/">mailing
list</a> can also be used.
----
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。