xref: /openbsd-src/bin/ksh/NOTES (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1$OpenBSD: NOTES,v 1.12 2013/11/28 10:33:37 sobrado Exp $
2
3General features of at&t ksh88 that are not (yet) in pdksh:
4    - exported aliases and functions (not in ksh93).
5    - set -t.
6    - signals/traps not cleared during functions.
7    - trap DEBUG, local ERR and EXIT traps in functions.
8    - ERRNO parameter.
9    - doesn't have posix file globbing (eg, [[:alpha:]], etc.).
10    - use of an `agent' to execute unreadable/setuid/setgid shell scripts
11      (don't ask).
12    - read/select aren't hooked in to the command line editor
13    - the last command of a pipeline is not run in the parent shell
14
15Known bugs (see also BUG-REPORTS and PROJECTS files):
16    Variable parsing, Expansion:
17	- some specials behave differently when unset (eg, IFS behaves like
18	  " \t\n") others lose their special meaning.  IFS/PATH taken care of,
19	  still need to sort out some others (eg, TMOUT).
20    Parsing,Lexing:
21	- line numbers in errors are wrong for nested constructs.  Need to
22	  keep track of the line a command started on (can use for LINENO
23	  parameter as well).
24	- a $(..) expression nested inside double quotes inside another $(..)
25	  isn't parsed correctly (eg, $(echo "foo$(echo ")")") )
26    Commands,Execution:
27	- setting special parameters that have side effects when
28	  changed/restored (ie, HISTFILE, OPTIND, RANDOM) in front
29	  of a command (eg, HISTFILE=/foo/bar echo hi) effects the parent
30	  shell.  Note that setting other (not so special) parameters
31	  does not effect the parent shell.
32	- `echo hi | exec cat -n' causes at&t to exit, `exec echo hi | cat -n'
33	  does not.  pdksh exits for neither.  Don't think POSIX requires
34	  an exit, but not sure.
35	- `echo foo | read bar; echo $bar' prints foo in at&t ksh, nothing
36	  in pdksh (ie, the read is done in a separate process in pdksh).
37    Misc:
38
39Known problems not caused by ksh:
40    - after stoping a job, emacs/vi is not re-entered.  Hitting return
41      prints the prompt and everything is fine again.  Problem (often
42      involving a pager like less) is related to order of process
43      scheduling (shell runs before `stop'ed (sub) processes have had a chance
44      to clean up the screen/terminal).
45
46Known differences between pdksh & at&t ksh (that may change)
47    - vi:
48	- `^U': at&t: kills only what has been inserted, pdksh: kills to
49	  start of line
50    - at&t ksh login shells say "Warning: you have running jobs" if you
51      try to exit when there are running jobs.  An immediate second attempt
52      to exit will kill the jobs and exit.  pdksh does not print a warning,
53      nor does it kill running jobs when it exits (it does warn/kill for
54      stopped jobs).
55    - TMOUT: at&t prints warning, then waits another 60 seconds.  If on screwed
56      up serial line, the output could cause more input, so pdksh just
57      prints a message and exits.  (Also, in at&t ksh, setting TMOUT has no
58      effect after the sequence "TMOUT=60; unset TMOUT", which could be
59      useful - pdksh may do this in the future).
60    - in pdksh, if the last command of a pipeline is a shell builtin, it is
61      not executed in the parent shell, so "echo a b | read foo bar" does not
62      set foo and bar in the parent shell (at&t ksh will).
63      This may get fixed in the future, but it may take a while.
64    - in pdksh, set +o lists the options that are currently set, in at&t ksh
65      it is the same as set -o.
66    - in pdksh emacs mode, ^T does what gnu emacs does, not what at&t ksh
67      does.
68    - in ksh93, `. name' calls a function (defined with function) with POSIX
69      semantics (instead of ksh semantics).  in pdksh, . does not call
70      functions.
71    - test: "test -f foo bar blah" is the same as "test -f foo" (the extra
72      arguments, of which there must be at least 2, are ignored) - pdksh
73      generates an error message (unexpected operator/operand "bar") as it
74      should.  Sometimes used to test file globs (e.g., if test -f *.o; ...).
75    - if the command 'sleep 5 && /bin/echo blah' is run interactively and
76      is the sleep is stopped (^Z), the echo is run immediately in pdksh.
77      In at&t ksh, the whole thing is stopped.
78    - LINENO:
79	- in ksh88 variable is always 1 (can't be changed) in interac mode;
80	  in pdksh it changes.
81	- Value of LINENO after it has been set by the script in one file
82	  is bizarre when used in another file.
83
84Known differences between pdksh & at&t ksh (that are not likely to change)
85    - at&t ksh seems to catch or ignore SIGALRM - pdksh dies upon receipt
86      (unless it's traped of course)
87    - typeset:
88	- at&t ksh overloads -u/-l options: for integers, means unsigned/long,
89	  for strings means uppercase/lowercase; pdksh just has the
90	  upper/lower case (which can be useful for integers when base > 10).
91	  unsigned/long really should have their own options.
92	- at&t ksh can't have justified integer variables
93	  (eg, typeset -iR5 j=10), pdksh can.
94	- in pdksh, number arguments for -L/-R/-Z/-i must follow the option
95	  character, at&t allows it at the end of the option group (eg,
96	  at&t ksh likes "typeset -iu5 j", pdksh wants "typeset -i5 -u j"
97	  or "typeset -ui5 j").  Also, pdksh allows "typeset -i 5 j" (same
98	  as "typeset -i5 j"), at&t ksh does not allow this.
99	- typeset -R: pdksh strips trailing space type characters (ie,
100	  uses isspace()), at&t ksh only skips blanks.
101	- at&t ksh allows attributes of read-only variables to be changed,
102	  pdksh allows only the export attribute to be set.
103    - (some) at&t ksh allows set -A of readonly variables, pdksh does not.
104    - at&t ksh allows command assignments of readonly variables (eg, YY=2 cat),
105      pdksh does not.
106    - at&t ksh does not exit scripts when an implicit assignment to an integer
107      variable fails due to an expression error: eg,
108		echo 2+ > /tmp/x
109		unset x; typeset -i x
110		read x < /tmp/x
111		echo still here
112      prints an error and then prints "still here", similarly for
113		unset x; typeset -i x
114		set +A x 1 2+ 3
115		echo still here
116      and
117		unset x y; typeset -i x y; set +A y 10 20 30
118		set +A x 1 1+y[2+] 3
119		echo still here
120      pdksh exits a script in all the above cases. (note that both shells
121      exit for:
122		unset x; typeset -i x
123		for x in 1 2+ 3; do echo x=$x; done
124		echo still here
125      ).
126    - at&t ksh seems to allow function calls inside expressions
127      (eg, typeset -i x='y(2)') but they do not seem to be regular functions
128      nor math functions (eg, pow, exp) - anyone known anything about this?
129    - `set -o nounset; unset foo; echo ${#foo}`: at&t ksh prints 0; pdksh
130      generates error.  Same for ${#foo[*]} and ${#foo[@]}.
131    - . file: at&t ksh parses the whole file before executing anything,
132      pdksh executes as it parses.  This means aliases defined in the file
133      will affect how pdksh parses the file, but won't affect how at&t ksh
134      parses the file.  Also means pdksh will not parse statements occurring
135      after a (executed) return statement.
136    - a return in $ENV in at&t ksh will cause the shell to exit, while in
137      pdksh it will stop executing the script (this is consistent with
138      what a return in .profile does in both shells).
139    - at&t ksh does file globbing for `echo "${foo:-"*"}"`, pdksh does not
140      (POSIX would seem to indicate pdksh is right).
141    - at&t ksh thinks ${a:##foo} is ok, pdksh doesn't.
142    - at&t does tilde expansion on here-document delimiters, pdksh does
143      not.  eg.
144	$ cat << ~michael
145	~michael
146	$
147      works for pdksh, not for at&t ksh (POSIX seems to agree with pdksh).
148    - in at&t ksh, tracked aliases have the export flag implicitly set
149      and tracked aliases and normal aliases live in the same name space
150      (eg, "alias" will list both tracked and normal aliases).
151      in pdksh, -t does not imply -x (since -x doesn't do anything yet), and
152      tracked/normal aliases live in separate name spaces.
153      in at&t ksh, alias accepts + options (eg, +x, +t) - pdksh does not.
154      in pdksh, alias has a -d option to allow examination/changing of
155      cached ~ entries, also unalias has -d and -t options (unalias -d
156      is useful if the ~ cache gets out of date - not sure how at&t deals
157      with this problem (it does cache ~ entries)).
158    - at&t ksh will stop a recursive function after about 60 calls; pdksh
159      will not since the limit is arbitrary and can't be controlled
160      by the user (hit ^C if you get in trouble).
161    - the wait command (with and without arguments) in at&t ksh will wait for
162      stopped jobs when job control is enabled.  pdksh doesn't.
163    - at&t ksh automatically sets the bgnice option for interactive shells;
164      pdksh does not.
165    - in at&t ksh, "eval `false`; echo $?" prints 1, pdksh prints 0 (which
166      is what POSIX says it should).  Same goes for "wait `false`; echo $?".
167      (same goes for "set `false`; echo $?" if posix option is set - some
168      scripts that use the old getopt depend on this, so be careful about
169      setting the posix option).
170    - in at&t ksh, print -uX and read -uX are interrperted as -u with no
171      argument (defaults to 1 and 0 respectively) and -X (which may or
172      may not be a valid flag).  In pdksh, -uX is interpreted as file
173      descriptor X.
174    - in at&t ksh, some signals (HUP, INT, QUIT) cause the read to exit, others
175      (ie, everything else) do not.  When it does cause exiting, anything read
176      to that point is used (usually an empty line) and read returns with 0
177      status.  pdksh currently does similar things, but for TERM as well and
178      the exit status is 128+<signal-number> - in future, pdksh's read will
179      do this for all signals that are normally fatal as required by POSIX.
180      (POSIX does not require the setting of variables to null so applications
181      shouldn't rely on this).
182    - in pdksh, ! substitution done before variable substitution; in at&t ksh
183      it is done after substitution (and therefor may do ! substitutions on
184      the result of variable substitutions).  POSIX doesn't say which is to be
185      done.
186    - pwd: in at&t ksh, it ignores arguments; in pdksh, it complains when given
187      arguments.
188    - the at&t ksh does not do command substition on PS1, pdksh does.
189    - ksh93 allows ". foo" to run the function foo if there is no file
190      called foo (go figure).
191    - field splitting (IFS): ksh88/ksh93 strip leading non-white space IFS
192      chars, pdksh (and POSIX, I think) leave them intact. e.g.
193	$ IFS="$IFS:"; read x; echo "<$x>"
194	::
195      prints "<>" in at&t ksh, "<::>" in pdksh.
196    - command completion: at&t ksh will do completion on a blank line (matching
197      all commands), pdksh does not (as this isn't very useful - use * if
198      you really want the list).
199    - co-processes: if ksh93, the write portion of the co-process output is
200      closed when the most recently started co-process exits. pdksh closes
201      it when all the co-processes using it have exited.
202    - pdksh accepts empty command lists for while and for statements, while
203      at&t ksh (and sh) don't.  Eg., pdksh likes
204	while false ; do done
205      but ksh88 doesn't like it.
206    - pdksh bumps RANDOM in parent after a fork, at&t ksh bumps it in both
207      parent and child:
208	RANDOM=1
209	echo child: `echo $RANDOM`
210	echo parent: $RANDOM
211      will produce "child: 16838 parent: 5758" in pdksh, while at&t ksh
212      will produce "child: 5758 parent: 5758".
213
214Oddities in ksh (pd & at&t):
215    - array references inside (())/$(()) are strange:
216	  $(( x[2] )) does the expected, $(( $x[2] )) doesn't.
217    - `typeset -R3 X='x '; echo "($X)"` produces (  x) - trailing
218      spaces are stripped.
219    - typeset -R turns off Z flag.
220    - both shells have the following mis-feature:
221	$ x='function xx {
222		cat -n <<- EOF
223		here we are in xx
224		EOF
225		}'
226	$ (eval "$x"; (sleep 2; xx) & echo bye)
227	[1] 1234
228	bye
229	$ xx: /tmp/sh1234.1: cannot open
230    - bizarre special handling of alias/export/readonly/typeset arguments
231	$ touch a=a; typeset a=[ab]; echo "$a"
232	a=[ab]
233	$ x=typeset; $x a=[ab]; echo "$a"
234	a=a
235	$
236    - both ignore SIGTSTP,SIGTTIN,SIGTTOU in exec'd processes when talking
237      and not monitoring (at&t ksh kind of does this).  Doesn't really make
238      sense.
239      (Note that ksh.att -ic 'set +m; check-sigs' shows TSTP et al aren't
240       ignored, while ksh.att -ic 'set +m^J check-sigs' does... very strange)
241    - when tracing (set -x), and a command's stderr is redirected, the trace
242      output is also redirected. so "set -x; echo foo 2> /tmp/O > /dev/null"
243      will create /tmp/foo with the lines "+ > /dev/null" and "+ echo foo".
244    - undocumented at&t ksh feature: FPATH is searched after PATH if no
245      executable is found, even if typeset -uf wasn't used.
246
247at&t ksh bugs:
248    [various versions:
249	MIPS m120 RISC/os 5.0: Version 11/16/88d
250	Dec alpha osf/1 v1.3:  OSF/1 Version 11/16/88d NLS
251	HP pa HP-UX 9.01:  Version 11/16/88
252     ]
253    - (only hpux)
254      $ _[2]=hi
255      Bus error (core dumped)
256    - (only riscos, hpux)
257      $ typeset x[
258      $
259    - (only osf/1)
260      $ A=B cat << EOF
261      .$A.
262      EOF
263      Segmentation fault(coredump)
264      $
265    - (only osf/1)
266      $ read "?foo "
267      foo Foo
268      $ set | grep Foo
269      =Foo
270      $
271    - (all)
272      $ typeset -i A
273      $ typeset -L3 A
274      $ typeset -l A
275      Illegal instruction (core dumped)
276    - (all)
277      $ for i in a b c ; do echo $i, ${i[2]}, ${i[10]} ; done
278      a, ,
279      a, , b
280      a, , c
281      $
282    - (all)
283      $ echo ${abc:-G { I } K }
284      G { I K }
285      $
286      $ abc=hi
287      $ echo ${abc:-G { I } K }
288      hi K }
289      $
290      The second echo should only have printed `hi'.
291    - (all)
292      $ echo ${abc:- > foo}
293      syntax error: > unexpected
294      $
295    - (all? hpux) read reads too much from pipe (when pipe isn't stdin)
296	print 'hi\nthere' | ksh 8<&0 0< /dev/tty
297	    $ read -u8 x
298	    $ print $x
299	    hi
300	    $ cat 0<&8
301	    $ read -u8 y
302	    $ print $y
303	    there
304	    $
305    - (all)
306	$ umask 0
307	$ umask
308	00
309	$
310    - (osf, mips, !hpux)
311	$ exec alias
312	alias: not found
313	(shell dead)
314    - (all) non-white space IFS in non-substitution not preserved
315	$ IFS="$IFS:"
316	$ echo : "$@"		# this is ok
317	:
318	$ echo :"$@"		# this should print : too (me thinks)
319
320	$
321    - (only osf/1)
322	$ set +m
323	$ sleep 1 &		# wait for a sec or two
324	$ jobs
325	Memory fault (core dumped)
326    - (all)
327	$ (sleep 1 & echo hi) &
328	[1] 123
329	$ [1] 234
330	hi
331    - (osf/1, mips)
332	$ getopts abc optc -a -b -c
333	$ getopts abc optc -a -b -c
334	$ getopts abc optc -a
335	Memory fault (core dumped)
336    - (osf/1) POSIX says OPTIND shall be initialized to 1
337	$ echo $OPTIND
338	0
339	$
340    - (osf/1 + others?)
341	$ typeset -ri r=10
342	$ let r=12
343	$ echo $r
344	12
345	$
346    - (osf/1 + others?)
347	$ typeset -i a
348	$ typeset -L3 a
349	Memory fault (core dumped)
350    - (osf/1 + others?): -L strips leading \ \t\n\r, -R only strips trailing
351      spaces
352	$ typeset -L3 x
353	$ x=' ^I^J^M 2'
354	$ echo "($x)"
355	(2  )
356	$ typeset -R3 y
357	$ x='2^I^J^M '
358	$ echo "($x)"
359	(^I^J^M)
360	$
361    - (osf/1 + others?)
362	$ typeset +i RANDOM
363	Memory fault (core dumped)
364    - (osf/1 + others?): -L/-R/-Z clear -l/-u after assignment and vise versa
365	$ typeset -u x=ab
366	$ echo "($x)"
367	(AB)
368	$ typeset -L4 x=def
369	$ echo "($x)"
370	(DEF )
371	$ typeset | grep ' x$'
372	leftjust 4 x
373	$
374	$ typeset -L4 x=def
375	$ echo "($x)"
376	(def )
377	$ typeset -u x=ab
378	$ echo "($x)"
379	(AB  )
380	$ typeset | grep ' x$'
381	uppercase x
382	$
383	$ typeset -i x
384	$ x='2()'
385	$ x='()'
386	$ x='2(4)'
387    - (osf/1, others?)
388	$ unset foo
389	$ echo "${foo:-"*"}"
390	<results of * expansion>
391	$
392    - (osf/1, others?)
393	$ alias blah
394	blah: alias not found
395	$ alias -x blah | grep blah
396	blah
397	$ type blah
398	Memory fault (core dumped)
399    - (osf/1, others?)
400	$ trap 'echo hi; false' ERR
401	$ false
402	hi
403	hi
404	....
405	Memory fault (core dumped)
406    - (osf/1, others?)
407	$ typeset +i ERRNO
408	Memory fault (core dumped)
409    - (osf/1, others?)
410	$ X=abcdef
411	$ echo ${X#a{b,c}e}	# does not match {} inside word part of ${..#..}
412	abcdefe}
413	$
414    - (osf/1, others?)
415	$ x=f=abcdef
416	$ echo ${f#a|abc}
417	def
418	$ echo ${f#abc|a}
419	bcdef
420	$ echo ${f#abc|a|d}
421	abcdef
422	$
423    - (osf/1, hp-ux, others?)
424	$ i() echo hi
425	$ typeset -f
426	function i
427	{
428	hi
429	$
430    - (osf/1, others?)
431	$ function X {
432		echo start of X
433		function Y {
434			echo in Y
435		}
436		echo end of X
437	}
438	$ X
439	start of X
440	end of X
441	$ typeset -f
442	function X
443	{
444		echo start of X
445		function Y {
446			echo in Y
447		}
448		echo end of X
449	}
450	function Y
451	{
452			echo in Y
453		echo end of X
454		}
455	}
456	$
457    - (osf/1, others?)
458	 $ while read x; do print -r "A $x"; done |&
459	 [1] 18212
460	 $ exec 8<&p
461	 $ kill %1
462	 Memory fault
463    - (osf/1, others?) Error only happens for builtin commands (/bin/echo works)
464	 $ while read x; do print -r "A $x"; done |&
465	 [1] 18212
466	 $ echo hi <&p
467	 hi
468	 $ echo hi <&p
469	 ksh: p: bad file unit number
470	 $ while read x; do print -r "A $x"; done |&
471	 ksh: process already exists
472	 $
473    - (osf/1, others?) in restricted shells, command -p should not work.
474	$ PATH=/tmp ksh -r
475	$ print hi | command -p cat -n
476	     1  hi
477	$
478    - (osf/1, others?) error message wrong for autoload files that don't define
479      functions
480	$ FPATH=/tmp
481	$ echo echo hi there > /tmp/aja
482	$ aja
483	hi there
484	ksh: echo:  not found
485	$
486    - (SunOS M-12/28/93d):
487	$ cat -n << X $(
488	> echo foo
489	> )
490	> X
491	> echo bar
492	)
493	./ksh93: X: cannot open [No such file or directory]
494	Memory fault (core dumped)
495
496POSIX sh questions (references are to POSIX 1003.2-1992)
497	- arithmetic expressions: how are empty expressions treated?
498	  (eg, echo $((  ))).  at&t ksh (and now pdksh) echo 0.
499	  Same question goes for `test "" -eq 0' - does this generate an error
500	  or, if not, what is the exit code?
501	- should tilde expansion occur after :'s in the word part of ${..=..}?
502	  (me thinks it should)
503	- if a signal is received during the execution of a built-in,
504	  does the builtin command exit or the whole shell?
505	- is it legal to execute last command of pipeline in current
506	  execution environment (eg, can "echo foo | read bar" set
507	  bar?)
508	- what action should be taken if there is an error doing a dup due
509	  to system limits (eg, not enough feil destriptors): is this
510	  a "redirection error" (in which case a script will exit iff the
511	  error occured while executing a special built-in)?
512	  IMHO, shell should exit script.  Couldn't find a blanket statement
513	  like "if shell encounters an unexpected system error, it shall
514	  exit non-interactive scripts"...
515
516POSIX sh bugs (references are to POSIX 1003.2-1992)
517	- in vi insert mode, ^W deletes to beginning of line or to the first
518	  blank/punct character (para at line 9124, section 3).  This means
519	  "foo     ^W" will do nothing.  This is inconsistent with the vi
520	  spec, which says delete preceding word including and interceding
521	  blanks (para at line 5189, section 5).
522	- parameter expansion, section 3.6.2, line 391: `in each case that a
523	  value of word is needed (..), word shall be subjected to tilde
524	  expansion, parameter expansion, ...'.  Various expansions should not
525	  be performed if parameter is in double quotes.
526	- the getopts description says assigning OPTIND a value other than 1
527	  produces undefined results, while the rationale for getopts suggests
528	  saving/restoring the OPTIND value inside functions (since POSIX
529	  functions don't do the save/restore automatically).  Restoring
530	  OPTIND is kind of dumb since getopts may have been in the middle
531	  of parsing a group of flags (eg, -abc).
532	- unclear whether arithmetic expressions (eg, $((..))) should
533	  understand C integer constants (ie, 0x123, 0177).  at&t ksh doesn't
534	  and neither does pdksh.
535	- `...` definition (3.6.3) says nothing about backslash followed by
536	  a newline, which sh and at&t ksh strip out completely.  e.g.,
537		$ show-args `echo 'X
538		Y'`
539		Number of args: 1
540			1: <XY>
541		$
542	  POSIX would indicate the backslash-newline would be preserved.
543	- does not say how "cat << ''" is to be treated (illegal, read 'til
544	  blank line, or read 'til eof).  at&t ksh reads til eof, bourne shell
545	  reads 'til blank line.  pdksh reads 'til blank line.
546