Skip to content
ksh93 compilation and installation

ksh93 compilation and installation

October 21, 2026

ksh93 compilation and installation

What is ksh93

ksh93 (KornShell 93) is a major version (93 series) of KornShell, the classic Unix Shell developed by David Korn at AT&T Bell Laboratories. It is both a powerful interactive command interpreter and an efficient scripting programming language.

In the traditional Unix/Linux ecosystem, ksh93 is often used to replace the standard Bourne shell (sh) or C shell (csh). It is popular because it combines the lightweight nature of the traditional shell with the characteristics of a modern high-level programming language.

Some of its features:

  1. Full POSIX compatibility: ksh93 strictly follows the POSIX standard and is backwards compatible with the early Bourne shell and old versions of KornShell (such as ksh88). Most old scripts can run directly without modification.
  2. Powerful arithmetic operation capabilities: supports advanced integer operations similar to C language syntax (supports 2~64 base) and double-precision floating point operations, without the need to additionally call external tools such as expr, bc or awk.
  3. Rich data structures: Supports indexed arrays (Indexed Arrays) and associative arrays (Associative Arrays (dictionaries)).
  4. Supports Compound Variables, which can be used to build a hierarchical namespace similar to a structure (Struct) through the period (.).
  5. Support name reference (Nameref, namely typeset -n), which greatly facilitates function parameter passing.
  6. Excellent performance and built-in tools: Since many standard tools are directly implemented as Shell built-in commands (Builtins), ksh93 is often much faster than traditional shells when executing complex scripts.
  7. Excellent scalability: Supports loading custom built-in commands through dynamic linking at runtime, and can even be embedded into C/C++ programs as shared libraries for calls.
  8. Typical application scenarios: large-scale enterprise-level automated operation and maintenance: Due to its strict logic control, rich string processing (supporting regular expressions, substring interception) and function scope control, it is very suitable for writing complex and large-scale automated operation and maintenance scripts. Cross-platform script porting: widely used in various commercial UNIX systems (such as AIX, Solaris, HP-UX) as well as modern Linux/embedded systems and Windows-compatible environments (such as MSYS2, Cygwin).

The current active branch of ksh93

The current active branch is this: ksh93 u+m.

For installation and compilation under Linux systems and Cygwin, just follow the official instructions and guidelines. However, there is currently no official solution for compilation under the msys2 environment of Windows. There is currently a BUG#801 that has not been resolved.

Compilation and installation of ksh93 in the msys2 environment of Windows

According to the discussion of BUG#801, we tried to compile and build under msys2.

build.sh :

#!/bin/sh
set -e

# [Soft link defense] Force MSYS2 to pull up real symbolic links at the Windows permission level
# Force MSYS2 to try to create a real Windows system-level soft link to avoid the build system reporting errors due to link failure
# Requires Windows Developer Mode or administrator rights to create real symbolic links
export MSYS="winsymlinks:sys"
# Enable POSIX and Windows NT permission security mapping to prevent permission denial when reading, writing and executing files.
export CYGWIN="ntsec"

# [Path Search] Automatically grab the real path of cc1.exe inside gcc and inject it into PATH
# Automatically capture the current internal core installation directory of gcc (including cc1.exe, collect2 and other back-end components)
export GCC_DIR="$(gcc -print-search-dirs | sed -ne '/^install: /s///p')"
# Append it to PATH to prevent old build systems from prompting "command not found" when calling the compiler component under the hood.
export PATH="$PATH:$GCC_DIR"

# [Compilation Environment Specification] Standardized C language compiler environment variables
# Explicitly specify the search paths for standard header files and library files to ensure that the compiler can accurately locate basic dependencies.
export CFLAGS="-I${GCC_DIR}/include -L${GCC_DIR} -L/usr/lib"


# Extended compilation flags specific to the AST/Mamfile build system
# core key:-fno-use-linker-plugin 
#   Function: Turn off the modern GCC linker plug-in (LTO plug-in).
#   Reason: To prevent modern linker plugins from colliding with older, non-standard build system packaging/linking processes and causing crashes.
export CCFLAGS="${CFLAGS} -fno-use-linker-plugin"


# Specifies a private directory where the GCC linker searches for library files at compile time
export LIBRARY_PATH="${GCC_DIR}"

# [Global Shebang added] Traverse all .sh scripts in the src directory, and insert the header safely into #!/bin/sh
if [ -d src ]; then
    echo "Safely padding the /bin/sh boot header for all .sh scripts in the src directory..."
    find src -name "*.sh" -type f | while read -r sh_file; do
        if ! head -n 1 "$sh_file" | grep -q "/bin/sh"; then
            sed -i '1s/^/#!\/bin\/sh\n/' "$sh_file"
        fi
    done
fi

# [UNC Compatible] Inject macro isolation patch into astconf.c in place before compilation
if [ -f src/lib/libast/port/astconf.c ]; then
    patch -p1 <ksh-unc-paths.patch
fi

# [Replace the old cygwin interface]
#   src/lib/libast/path/pathnative.c
#   src/lib/libast/path/pathposix.c

sed -Ei '/^\s*extern\s+void\s+.*cygwin_conv_to_win32_path/c\#include <sys/cygwin.h>' "src/lib/libast/path/pathnative.c"
sed -i 's/cygwin_conv_to_win32_path(path, tmp);/cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, tmp, PATH_MAX);/g' "src/lib/libast/path/pathnative.c"
sed -i 's/cygwin_conv_to_win32_path(path, buf);/cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, buf, siz);/g' "src/lib/libast/path/pathnative.c"

sed -Ei '/^\s*extern\s+void\s+.*cygwin_conv_to_posix_path/c\#include <sys/cygwin.h>' "src/lib/libast/path/pathposix.c"
sed -i 's/cygwin_conv_to_posix_path(path, tmp);/cygwin_conv_path(CCP_WIN_A_TO_POSIX, path, tmp, PATH_MAX);/g' "src/lib/libast/path/pathposix.c"
sed -i 's/cygwin_conv_to_posix_path(path, buf);/cygwin_conv_path(CCP_WIN_A_TO_POSIX, path, buf, siz);/g' "src/lib/libast/path/pathposix.c"

# [Macro Conflict Interception] Forcibly remove system iconv macro definition confusion
if [ -f src/lib/libast/features/iconv ]; then
    sed -i '6s/^/#undef _lib_iconv_open\n/' src/lib/libast/features/iconv
fi

# [Environment variables ready] Add the local target compilation bin directory to PATH
TARGET_BIN="$PWD/arch/cygwin.i386/bin"
mkdir -p bin "$TARGET_BIN"
export PATH="$PWD/bin:$TARGET_BIN:$PATH"

echo "[Phase 1] Start the first round of compilation (it is normal if interruption is caused by the fragile fork mechanism of Windows)..."
CC="/usr/bin/gcc" /bin/sh bin/package make PACKAGEROOT="$PWD" || true

# [Detection] Check whether the target ksh binary file has been successfully generated
KSH_BIN=$(ls arch/*/bin/ksh 2>/dev/null || true)

if [ -n "$KSH_BIN" ] && [ -f "$KSH_BIN" ]; then
    echo "[Skip] Detected ksh binary successfully generated in first round!"
else
    echo "[Phase 2] It is found that the binary is not ready yet, and the second round of in-situ resurrection compilation is started..."
    CC="/usr/bin/gcc" /bin/sh bin/package make PACKAGEROOT="$PWD"
fi

echo "=========================================================="
echo "Congratulations, man! Rigorous [complete body] Ksh93 u+m binary file compiled successfully!"
echo "Your native ksh.exe is already safely located in the following path:"
ls -l arch/*/bin/ksh
echo "=========================================================="

# Automatically find the compiled ksh and install it to /usr/local/bin/ksh
KSH_SRC=$(ls arch/*/bin/ksh 2>/dev/null)

if [ -f "$KSH_SRC" ]; then
    echo "[Standardized Installation] Deploying ksh to /usr/local/bin/..."
    install -Dm755 "$KSH_SRC" /usr/local/bin/ksh
    echo "Installation successful! Now you can call it directly by typing ksh anywhere."
else
    echo "The compiled ksh binary file was not found, please compile first!"
    exit 1
fi

# Check and write safely to /etc/shells
KSH_PATH="/usr/local/bin/ksh"

if ! grep -qxF "$KSH_PATH" /etc/shells; then
    echo "[Registration Shell] Writing $KSH_PATH to /etc/shells..."
    echo "$KSH_PATH" >> /etc/shells
    echo "Registration completed!"
else
    echo "/etc/shells the path already exists in the directory and registration is skipped."
fi

# test
./arch/cygwin.i386/bin/ksh.exe --version
./arch/cygwin.i386/bin/ksh.exe -c 'typeset -A user=( [name]="qindapao" [status]="Legendary" );print -r -- "Author: ${user[name]}, Build Status: ${user[status]}"; print -r -- "Math test: $(( 3.14159 * 2 ))"'

ksh-unc-paths.patch :

diff --git a/src/lib/libast/port/astconf.c b/src/lib/libast/port/astconf.c
index b6b58027..396cd46d 100644
--- a/src/lib/libast/port/astconf.c
+++ b/src/lib/libast/port/astconf.c
@@ -1355,6 +1355,24 @@ astgetconf(const char* name, const char* path, const char* value, int flags, Err
	Lookup_t	look;
	Sfio_t*		tmp;

+#ifdef __CYGWIN__
+	/*
+	 * hack for Cygwin to make Cygwin UNC paths (with leading
+	 * two slashes) work.
+	 *
+	 * Testcase:
+	 * cd into UNC path, print "pwd -P", result must start with
+	 * "//<hostname>/<path>"
+	 * ---- snip ----
+	 * $ bash -c 'cd "//derfw1fs10.global.loc/rfw" ; path_to_kshdir/ksh.exe -c "pwd -P ; true" ; true'
+	 * //derfw1fs10.global.loc/rfw
+	 * ---- snip ----
+	 *
+	 */
+	if (name && (!strcmp(name, "PATH_LEADING_SLASHES"))) {
+		return "1";
+	}
+#endif /* __CYGWIN__ */
	if (!name)
	{
		if (path)

The final compiled product is 1.4 M in size and seems to work.

  version         sh (AT&T Research) 93u+m/1.1.0-alpha 2026-10-22
Author: qindapao, Build Status: Legendary
Math test: 6.28318
admin@DESKTOP-AQBA715 UCRT64 /d/temp/2026-10/ksh-dev$ ls

ksh93 slow execution problem on msys2

When a large number of Windows native paths are mixed into PATH, MSYS2 needs to perform POSIX conversion and mount table matching on each path during the process startupphase. During cold start, this overhead will be superimposed with disk reading and security software scanning, which will significantly slow down the first startup; after the path is streamlined, the overhead of the first startup will also decrease.

Note: It is normal for the system to run slowly for the first time and then become faster later. It is usually related to the Windows file cache and the first scan of the security software. It does not mean that PATH optimization is invalid.

# Keep the MSYS2 core path and remove the Windows native redundant path
export PATH=/ucrt64/bin:/usr/bin:/usr/local/bin

The way to locate this problem is as follows:

strace -f -o /tmp/ksh_full.log /usr/bin/ksh --version

Use the -o option to import the information during the strace tracing process into a file to facilitate analysis of slow program startup problems. Uninterrupted by ksh’s own printing.


✍️ Author of this article:秦大炮 (Qindapao)

Technical exchanges and reprints are welcome. Please indicate the source when reprinting and retain the following hard-core contact information.


Last updated on