ksh93很难避免子外壳。部分原因是避免了stdio以及sfio的广泛使用,它允许内置程序直接进行通信。另一个原因是,ksh理论上可以具有这么多的内置函数。如果使用构建
SHOPT_CMDLIB_DIR,则默认情况下将包括并启用所有cmdlib内置插件。我无法提供避免使用子shell的完整列表,但通常仅在使用内置插件且没有重定向的情况下使用。
#!/usr/bin/env ksh# doCompat arr# "arr" is an indexed array name to be assigned an index corresponding to the detected shell.# 0 = Bash, 1 = Ksh93, 2 = mkshfunction doCompat { ${1:+:} return 1 if [[ ${BASH_VERSION+_} ]]; then shopt -s lastpipe extglob eval "${1}[0]=" else case "${BASH_VERSINFO[*]-${!KSH_VERSION}}" in .sh.version) nameref v=$1 v[1]= if builtin pids; then function BASHPID.get { .sh.value=$(pids -f '%(pid)d'); } elif [[ -r /proc/self/stat ]]; then function BASHPID.get { read -r .sh.value _ </proc/self/stat; } else function BASHPID.get { .sh.value=$(exec sh -c 'echo $PPID'); } fi 2>/dev/null ;; KSH_VERSION) nameref "_${1}=$1" eval "_${1}[2]=" ;& *) if [[ ! ${BASHPID+_} ]]; then echo 'BASHPID requires Bash, ksh93, or mksh >= R41' >&2 return 1 fi esac fi}function main { typeset -a myShell doCompat myShell || exit 1 # stripped-down compat function. typeset x print -v .sh.version x=$(print -nv BASHPID; print -nr " $$"); print -r "$x" # comsubs are free for builtins with no redirections _=$({ print -nv BASHPID; print -r " $$"; } >&2) # but not with a redirect _=$({ printf '%s ' "$BASHPID" $$; } >&2); echo # nor for expansions with a redirect _=$(printf '%s ' "$BASHPID" $$ >&2); echo # but if expansions aren't redirected, they occur in the same process. _=${ { print -nv BASHPID; print -r " $$"; } >&2; } # However, ${ ;} is always subshell-free (obviously). ( printf '%s ' "$BASHPID" $$ ); echo # Basically the same rules apply to ( ) read -r x _ <<<$(</proc/self/stat); print -r "$x $$" # These are free in {{m,}k,z}sh. only Bash forks for this. printf '%s ' "$BASHPID" $$ | cat # Sadly, pipes always fork. It isn't possible to precisely mimic "printf -v". echo} 2>&1main "$@"出:
Version AJM 93v- 2013-02-2231732 3173231735 3173231736 31732 31732 31732 31732 3173231732 31732 31732 3173231738 31732
所有这些内部I /
O处理的另一个很好的结果就是一些缓冲问题就消失了。这是读取带有
tee和
head内置的代码行的有趣示例(请勿在任何其他shell中尝试)。
$ ksh -s <<EOFinteger -a xbuiltin head teeprintf %s\n {1..10} | while head -n 1 | [[ ${ { x+=("$(tee /dev/fd/{3,4})"); } 3>&1; } ]] 4>&1; do print -r -- "${x[@]}" doneEOF10 120 1 230 1 2 340 1 2 3 450 1 2 3 4 560 1 2 3 4 5 670 1 2 3 4 5 6 780 1 2 3 4 5 6 7 890 1 2 3 4 5 6 7 8 9100 1 2 3 4 5 6 7 8 9 10


