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