Codebase list mksh / 6a337df5-67d8-428a-8e0c-7a68acd12d96/main mksh.faq
6a337df5-67d8-428a-8e0c-7a68acd12d96/main

Tree @6a337df5-67d8-428a-8e0c-7a68acd12d96/main (Download .tar.gz)

mksh.faq @6a337df5-67d8-428a-8e0c-7a68acd12d96/mainraw · history · blame

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
RCSID: $MirOS: src/bin/mksh/mksh.faq,v 1.32+locale-tracking 2022/01/25 06:07:32 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, 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 Ive run into this one, didnt I? MirBSD is pronounced <span
 xml:lang="de-DE-1901">Mir-Be-Es-De</span> germanically, for anglophones
 Mir-beastie 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>
----
ToC: sowhatismksh
Title: Im a $OS (<i>Android, OS/2, </i>) user, so whats 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. Its
 also used to write so-called (shell) scripts, short programs made by
 putting several of those commands into a batch file.</p>
<p>On Android, mksh is used as the system shellbasically, 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&amp;postcount=1553">not
 caused by mksh</a> but by some other code invoking mksh to do something
 on its behalf.</p>
----
ToC: os2
Title: Im 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 komhs 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&amp;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>Theres 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&amp;T ksh88 is the (original) Korn Shell. Other implementations,
 of varying quality (MKS Toolkits MKS ksh being named as an example of
 the lower end, MirBSDs 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&amp;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&amp;Ts was proprietary,
 closed-source code for a very long time. pdkshs 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 OpenBSDs 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&amp;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 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, thats 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 Debians</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 &lt;<i>some other shell</i>&gt; 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 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>
----
ToC: env
Title: On startup files and <tt>$ENV</tt> across and detecting various shells

<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="@@RELPATH@@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&amp;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>
----
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: escaping
Title: Some characters don’t display right

<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>
----
ToC: carets
Title: What’s with these ^Q, ^!Q and ^+Q (e.g. from tab completion)? \x80 too!

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.
----
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 you want it to only delete the line up to the cursor, use:<br />
<tt>bind -m ^U='^[0^K'</tt>
----
ToC: ctrl-w-bash
Title: ^W (Ctrl-W) deletes a word, not a bigword

If you want it to delete more, with R60 you can use:<br />
<tt>bind '^W=delete-bigword-backward'</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 &gt;/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 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> <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-10000080‥U-100000FF,
 which is outside the UCS and therefore collision-free. There’s work underway
 to make the shell support the full 21-bit UCS range for R60.</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">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>
----
ToC: function-local-scopes
Title: What differences in function-local scopes are there?

<p><tt>mksh</tt> has a different scope model from AT&amp;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: local-arrays
Title: How can I do local arrays?

<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>
	function foo {
		a[1]=x		# modifies the outer array
		echo ${a[*]}
		local a		# makes a local variable…
		set -A a	# … of type array…
		a[0]=yz		# modifies the inner array
		echo ${a[*]}
		unset a		# removes the local variable
		echo ${a[*]}
		a[2]=!		# modifies the unveiled outer again
		echo ${a[*]}
	}
	set -A a -- 1 2 3 4 5
	echo ${a[*]}		# shows the outer array before…
	foo
	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&amp;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>
----
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>&amp;&gt;</tt>” (and “<tt>|&amp;</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 |&amp; bar |&amp; baz &amp;&gt;log</tt>
 </td></tr>
 <tr><td>POSIX</td><td>
  <tt>foo 2&gt;&amp;1 | bar 2&gt;&amp;1 | baz &gt;log 2&gt;&amp;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 |&amp;
	while read -p foo; do ...; done
	exec 3&gt;&amp;p; exec 3&gt;&amp;-
 </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 &lt;file</tt>);
 the same applies for NUL-terminated lines:</p>
<div class="boxtext">
 <pre>
	find . -type f -print0 |&amp; \
	    while IFS= read -d '' -pr filename; do
		print -r -- "found &lt;${filename#./}&gt;"
	done
 </pre>
</div>
----
ToC: command-alias
Title: “command” doesn’t expand aliases as in ksh93

This is because AT&amp;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-cat
Title: Didn’t there used to be a cat(1) builtin?

<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>
----
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 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>
----
ToC: builtin-sleep
Title: Didn’t there used to be a sleep(1) builtin?

<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="@@RELPATH@@subprj.htm#sleep">a
 portable sleep</a> which similarily 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>
----
ToC: arith-import
Title: Some integer variables are 0?

<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>
	foo=1+1 mksh -c 'integer foo; print $foo'
	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>
----
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" &amp;&amp; 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" &amp;&amp; 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&amp;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 &amp;&amp; echo $x
	done | cat
 </pre>
</div><p class="boxfoot">This is because, while the <tt>&amp;&amp;</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) and lksh(1) manual page. You might also wish to read the <a
 href="@@RELPATH@@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).
----
ToC: contact
Title: How do I contact you (to say thanks, for bugreports and questions)?

<p>You can say hi in the <tt>#!/bin/mksh</tt> channel on <a
 href="@@RELPATH@@irc.htm">IRC</a> (OFTC, for now), although… a
 <a href="@@RELPATH@@danke.htm">donation</a> wouldn’t be amiss ☻
<br />The <a href="@@RELPATH@@rss.htm#lists">mailing list</a> can also
 be used for this. 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 and the mailing list 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>
----