Skip to content

ksh - Korn Shell

The Korn Shell (ksh) is a powerful Unix shell developed by David Korn at Bell Labs, first released in 1983. As a superset of the Bourne shell (sh), ksh combines POSIX compliance with advanced programming features, making it particularly popular in enterprise environments and among system administrators who require robust scripting capabilities. The Korn shell offers superior performance, extensive built-in functionality, and sophisticated programming constructs while maintaining backward compatibility with traditional shell scripts. It serves as a bridge between the simplicity of POSIX sh and the advanced features found in modern shells.

Installation and Setup

Korn Shell Variants

ksh
# Check which ksh variant is installed
echo $KSH_VERSION
# Output examples:
# Version AJM 93u+ 2012-08-01  (ksh93)
# Version JM 93t+ 2010-03-05   (ksh93)

# Common ksh implementations
which ksh                       # System ksh
which ksh93                     # AT&T ksh93
which mksh                      # MirBSD Korn Shell
which pdksh                     # Public Domain Korn Shell

# Check shell features
print $(.sh.version) 2>/dev/null || echo "Not ksh93"

Installing Korn Shell

ksh
# Ubuntu/Debian
sudo apt update && sudo apt install ksh

# For ksh93 specifically
sudo apt install ksh93

# CentOS/RHEL/Fedora
sudo dnf install ksh

# macOS (using Homebrew)
brew install ksh93

# Arch Linux
sudo pacman -S ksh

# FreeBSD
pkg install ksh93

# From source (ksh93)
git clone https://github.com/att/ast.git
cd ast
bin/package make

Setting ksh as Default Shell

ksh
# Check ksh installation
which ksh
/bin/ksh

# Add ksh to available shells
echo /bin/ksh | sudo tee -a /etc/shells

# Set ksh as default shell
chsh -s /bin/ksh

# Verify change (restart terminal)
echo $SHELL
/bin/ksh

# Check ksh version and features
echo $KSH_VERSION
set | grep KSH

Basic Configuration

ksh
# Create .kshrc for interactive shell configuration
cat > ~/.kshrc << 'EOF'
# Korn Shell configuration

# Set environment variables
export EDITOR=vi
export PAGER=less
export HISTSIZE=1000

# Set prompt
PS1='${USER}@${HOSTNAME}:${PWD}$ '

# Aliases
alias ll='ls -l'
alias la='ls -la'
alias h='history'

# Enable vi editing mode
set -o vi

# History options
set -o trackall
EOF

# Set ENV variable to load .kshrc
export ENV=~/.kshrc
echo 'export ENV=~/.kshrc' >> ~/.profile

Ksh-Specific Features and Syntax

Variable Types and Declarations

ksh
# Integer variables
typeset -i num=10
integer count=0
count+=5                        # count is now 5

# Floating point variables (ksh93)
typeset -F2 price=19.99         # 2 decimal places
float temperature=98.6

# Array variables
typeset -a fruits
fruits=(apple banana orange)
set -A colors red green blue    # Alternative syntax

# Associative arrays (ksh93)
typeset -A config
config[host]=localhost
config[port]=8080

# Read-only variables
typeset -r CONSTANT="unchangeable"
readonly PI=3.14159

# Exported variables
typeset -x PATH="/usr/local/bin:$PATH"
export LANG=en_US.UTF-8

Advanced Parameter Expansion

ksh
# String manipulation
string="Hello, World!"
print ${#string}                # Length: 13
print ${string#Hello}           # Remove from beginning: , World!
print ${string%World!}          # Remove from end: Hello, 
print ${string/Hello/Hi}        # Replace first: Hi, World!
print ${string//l/L}            # Replace all: HeLLo, WorLd!

# Case conversion (ksh93)
print ${string^^}               # Uppercase: HELLO, WORLD!
print ${string,,}               # Lowercase: hello, world!
print ${string^}                # Capitalize first: Hello, world!

# Substring extraction
print ${string:0:5}             # First 5 characters: Hello
print ${string:7}               # From position 7: World!
print ${string:(-6)}            # Last 6 characters: World!

# Default values
print ${undefined:-"default"}   # Use default if undefined
print ${undefined:="default"}   # Set default if undefined
print ${defined:+"alternate"}   # Use alternate if defined

Arrays and Associative Arrays

ksh
# Indexed arrays
typeset -a numbers
numbers=(1 2 3 4 5)
numbers[10]=100                 # Sparse array

# Array operations
print ${numbers[0]}             # First element
print ${numbers[@]}             # All elements
print ${#numbers[@]}            # Number of elements
print ${!numbers[@]}            # All indices

# Array assignment
numbers+=(6 7 8)               # Append elements
unset numbers[2]               # Remove element

# Associative arrays (ksh93)
typeset -A person
person[name]="John Doe"
person[age]=30
person[city]="New York"

# Iterate over associative array
for key in "${!person[@]}"; do
    print "$key: ${person[$key]}"
done

# Multi-dimensional arrays (ksh93)
typeset -A matrix
matrix[1,1]=a
matrix[1,2]=b
matrix[2,1]=c
matrix[2,2]=d

Arithmetic and Mathematical Operations

ksh
# Arithmetic expansion
result=$((5 + 3 * 2))           # 11
result=$((2 ** 8))              # 256 (exponentiation)

# Arithmetic with variables
typeset -i x=10 y=3
result=$((x / y))               # Integer division: 3
remainder=$((x % y))            # Modulo: 1

# Floating point arithmetic (ksh93)
typeset -F result
result=$((10.0 / 3.0))          # 3.333333

# Mathematical functions (ksh93)
result=$((sin(3.14159/2)))      # Sine function
result=$((sqrt(16)))            # Square root
result=$((log(10)))             # Natural logarithm
result=$((exp(2)))              # Exponential function

# Increment and decrement
((x++))                         # Post-increment
((++x))                         # Pre-increment
((x--))                         # Post-decrement
((--x))                         # Pre-decrement
((x += 5))                      # Add and assign

Advanced I/O and Redirection

ksh
# Co-processes
print -p "command"              # Send to co-process
read -p response                # Read from co-process

# File descriptors
exec 3< input.txt               # Open file for reading
exec 4> output.txt              # Open file for writing
read line <&3                   # Read from fd 3
print "data" >&4                # Write to fd 4
exec 3<&-                       # Close fd 3
exec 4>&-                       # Close fd 4

# Here strings
command <<< "input string"

# Process substitution (ksh93)
diff <(sort file1) <(sort file2)
command > >(process_output)

# Network I/O (ksh93)
exec 5<>/dev/tcp/hostname/port
print -u5 "GET / HTTP/1.0\n"
read -u5 response

Control Structures and Flow Control

Enhanced Conditional Statements

ksh
# [[ ]] conditional (preferred in ksh)
if [[ $string == pattern* ]]; then
    print "String starts with pattern"
fi

if [[ $string =~ regex ]]; then
    print "String matches regex"
fi

if [[ -f $file && -r $file ]]; then
    print "File exists and is readable"
fi

# Pattern matching in conditionals
case $filename in
    *.@(txt|doc|pdf))
        print "Document file"
        ;;
    *.@(jpg|png|gif))
        print "Image file"
        ;;
    *)
        print "Unknown file type"
        ;;
esac

# Numeric comparisons
if (( num > 10 && num < 100 )); then
    print "Number is between 10 and 100"
fi

Advanced Loop Constructs

ksh
# For loops with ranges
for i in {1..10}; do
    print "Number: $i"
done

for i in {1..10..2}; do         # Step by 2
    print "Odd number: $i"
done

# C-style for loops
for ((i=1; i<=10; i++)); do
    print "Counter: $i"
done

# For loops with arrays
for element in "${array[@]}"; do
    print "Element: $element"
done

# While loops with advanced conditions
while (( count < limit )); do
    print "Count: $count"
    ((count++))
done

# Until loops
until [[ -f ready.flag ]]; do
    print "Waiting for ready flag..."
    sleep 2
done

# Select loops for menus
select option in "Option 1" "Option 2" "Option 3" "Quit"; do
    case $option in
        "Option 1")
            print "You selected option 1"
            ;;
        "Option 2")
            print "You selected option 2"
            ;;
        "Option 3")
            print "You selected option 3"
            ;;
        "Quit")
            break
            ;;
        *)
            print "Invalid selection"
            ;;
    esac
done

Exception Handling

ksh
# Trap signals and errors
cleanup() {
    print "Cleaning up..."
    rm -f temp_files
    exit 1
}

trap cleanup INT TERM EXIT

# Error handling with ERR trap
error_handler() {
    print "Error occurred in line $1"
    exit 1
}

trap 'error_handler $LINENO' ERR
set -e                          # Exit on error

# Try-catch equivalent using functions
try() {
    "$@"
    return $?
}

catch() {
    case $? in
        0) return 0 ;;
        *) 
            print "Error: $1"
            return 1
            ;;
    esac
}

# Usage
if try risky_command; then
    print "Command succeeded"
else
    catch "Command failed"
fi

Functions and Advanced Programming

Function Definition and Features

ksh
# Basic function definition
function greet {
    print "Hello, $1!"
}

# Alternative syntax
greet() {
    print "Hello, $1!"
}

# Function with local variables
function calculate_stats {
    typeset -i sum=0 count=0
    typeset -F average
    
    for num in "$@"; do
        ((sum += num))
        ((count++))
    done
    
    if ((count > 0)); then
        ((average = sum / count))
        print "Sum: $sum, Count: $count, Average: $average"
    fi
}

# Function with return value
function is_prime {
    typeset -i num=$1 i
    
    if ((num < 2)); then
        return 1
    fi
    
    for ((i = 2; i * i <= num; i++)); do
        if ((num % i == 0)); then
            return 1
        fi
    done
    
    return 0
}

# Usage
if is_prime 17; then
    print "17 is prime"
fi

Advanced Function Features

ksh
# Function with named parameters (ksh93)
function process_file {
    typeset file="$1" mode="${2:-read}" verbose="${3:-false}"
    
    [[ $verbose == true ]] && print "Processing $file in $mode mode"
    
    case $mode in
        read)
            cat "$file"
            ;;
        write)
            print "Writing to $file"
            ;;
        *)
            print "Unknown mode: $mode" >&2
            return 1
            ;;
    esac
}

# Recursive functions
function factorial {
    typeset -i n=$1
    
    if ((n <= 1)); then
        print 1
    else
        print $((n * $(factorial $((n - 1)))))
    fi
}

# Function with variable number of arguments
function sum_all {
    typeset -i total=0
    
    while (($# > 0)); do
        ((total += $1))
        shift
    done
    
    print $total
}

# Function libraries and namespaces (ksh93)
namespace math {
    function add { print $(($1 + $2)); }
    function multiply { print $(($1 * $2)); }
}

# Usage
result=$(math.add 5 3)

Co-processes and Background Jobs

ksh
# Start co-process
command |&
coproc_pid=$!

# Communicate with co-process
print -p "input data"
read -p response

# Background job management
long_running_command &
job_pid=$!

# Wait for specific job
wait $job_pid

# Job control
jobs                            # List active jobs
fg %1                          # Bring job 1 to foreground
bg %1                          # Send job 1 to background
kill %1                        # Kill job 1

# Disown jobs
disown %1                      # Remove job from job table

Built-in Commands and Utilities

Ksh Built-in Commands

ksh
# print command (preferred over echo)
print "Simple message"
print -n "No newline"
print -r "Raw output (no escape processing)"
print -u2 "Output to stderr"

# printf for formatted output
printf "%s: %d\n" "Count" 42
printf "%-10s %5d\n" "Name" 123

# read with advanced options
read var                       # Read single variable
read -r line                   # Raw read (no backslash processing)
read -t 10 input              # Read with timeout
read -s password              # Silent read (no echo)
read -A array                 # Read into array

# typeset for variable attributes
typeset -i integer_var=10
typeset -F2 float_var=3.14
typeset -u upper_var="hello"   # Uppercase
typeset -l lower_var="HELLO"   # Lowercase
typeset -r readonly_var="constant"

# whence command (which equivalent)
whence command                 # Show command type
whence -v command             # Verbose output
whence -a command             # Show all matches

String Processing

ksh
# String comparison and matching
[[ $string == pattern ]]       # Pattern matching
[[ $string != pattern ]]       # Pattern non-matching
[[ $string < other ]]          # Lexicographic comparison
[[ $string > other ]]          # Lexicographic comparison

# Pattern matching with extended globs
[[ $filename == *.@(txt|doc) ]] # Match .txt or .doc
[[ $string == +([0-9]) ]]      # Match one or more digits
[[ $string == ?([+-])+([0-9]) ]] # Optional sign, required digits

# String manipulation functions (ksh93)
string="Hello, World!"
print ${string/World/Universe}  # Replace first occurrence
print ${string//l/L}           # Replace all occurrences
print ${string#*,}             # Remove up to first comma
print ${string%,*}             # Remove from last comma

File and Directory Operations

ksh
# File testing
[[ -e file ]]                  # File exists
[[ -f file ]]                  # Regular file
[[ -d dir ]]                   # Directory
[[ -L link ]]                  # Symbolic link
[[ -r file ]]                  # Readable
[[ -w file ]]                  # Writable
[[ -x file ]]                  # Executable
[[ -s file ]]                  # Non-empty file

# File comparison
[[ file1 -nt file2 ]]          # file1 newer than file2
[[ file1 -ot file2 ]]          # file1 older than file2
[[ file1 -ef file2 ]]          # Same file (hard links)

# Directory operations
cd directory                   # Change directory
pushd directory               # Push directory onto stack
popd                          # Pop directory from stack
dirs                          # Show directory stack

# File globbing with extended patterns
ls *.@(txt|doc)               # Files ending in .txt or .doc
ls +([0-9]).txt               # Files with numeric names
ls !(*.tmp)                   # All files except .tmp files

Configuration and Customization

Environment and Shell Options

ksh
# Shell options
set -o vi                      # Vi editing mode
set -o emacs                   # Emacs editing mode
set -o trackall               # Track all commands for hashing
set -o monitor                # Enable job control
set -o notify                 # Report job status immediately
set -o noglob                 # Disable filename expansion
set -o noclobber              # Prevent output redirection from overwriting

# History options
set -o hist                   # Enable command history
HISTSIZE=1000                 # History size in memory
HISTFILE=~/.ksh_history       # History file location

# Prompt customization
PS1='${USER}@${HOSTNAME}:${PWD##*/}$ '
PS2='> '                      # Continuation prompt
PS3='#? '                     # Select prompt
PS4='+ '                      # Debug prompt

# Advanced prompt with functions
function set_prompt {
    typeset git_branch=""
    if [[ -d .git ]]; then
        git_branch=" ($(git branch --show-current 2>/dev/null))"
    fi
    PS1="${USER}@${HOSTNAME}:${PWD##*/}${git_branch}$ "
}

# Set prompt command (ksh93)
PROMPT_COMMAND=set_prompt

Aliases and Functions

ksh
# Simple aliases
alias ll='ls -l'
alias la='ls -la'
alias h='history'
alias ..='cd ..'
alias ...='cd ../..'

# Aliases with parameters (use functions instead)
function mkcd {
    mkdir -p "$1" && cd "$1"
}

function extract {
    case $1 in
        *.tar.gz|*.tgz) tar xzf "$1" ;;
        *.tar.bz2|*.tbz2) tar xjf "$1" ;;
        *.zip) unzip "$1" ;;
        *.rar) unrar x "$1" ;;
        *) print "Unknown archive format" ;;
    esac
}

# Conditional aliases
if whence -q vim; then
    alias vi=vim
fi

# Platform-specific aliases
case $(uname) in
    Linux)
        alias ls='ls --color=auto'
        ;;
    Darwin)
        alias ls='ls -G'
        ;;
esac

Completion and Editing

ksh
# Command line editing
set -o vi                      # Vi editing mode
set -o emacs                   # Emacs editing mode (default)

# Key bindings (vi mode)
# Esc: Enter command mode
# i: Insert mode
# a: Append mode
# A: Append at end of line
# I: Insert at beginning of line
# dd: Delete line
# yy: Yank (copy) line
# p: Paste

# Key bindings (emacs mode)
# Ctrl+A: Beginning of line
# Ctrl+E: End of line
# Ctrl+K: Kill to end of line
# Ctrl+U: Kill to beginning of line
# Ctrl+W: Kill previous word
# Ctrl+Y: Yank (paste)
# Ctrl+R: Reverse search

# Tab completion (basic)
set -o complete               # Enable completion

Performance and Optimization

Performance Features

ksh
# Built-in commands vs external commands
# Use built-ins when possible for better performance
typeset -i count=0            # Built-in integer arithmetic
((count++))                   # Built-in increment

# String operations
string="Hello, World!"
print ${#string}              # Built-in length
print ${string%World*}        # Built-in pattern removal

# Array operations
typeset -a array=(1 2 3 4 5)
print ${#array[@]}            # Built-in array length

# Avoid subshells when possible
# Slow: result=$(command)
# Fast: command | read result (when appropriate)

# Use co-processes for repeated communication
command |&
for data in "${input_data[@]}"; do
    print -p "$data"
    read -p result
    process_result "$result"
done

Memory Management

ksh
# Unset variables when no longer needed
unset large_array
unset temporary_variable

# Use local variables in functions
function process_data {
    typeset -a local_array
    typeset local_var
    
    # Process data with local variables
    # Variables are automatically cleaned up
}

# Limit history size
HISTSIZE=500                  # Reasonable history size

Debugging and Profiling

ksh
# Debug mode
set -x                        # Print commands as executed
set +x                        # Disable debug mode

# Verbose mode
set -v                        # Print input lines as read
set +v                        # Disable verbose mode

# Function tracing
function trace_function {
    print "Entering function: ${.sh.fun}" >&2
    print "Arguments: $*" >&2
}

# Performance timing
function time_function {
    typeset start_time end_time
    start_time=$(date +%s%N)
    
    "$@"                      # Execute command
    
    end_time=$(date +%s%N)
    print "Execution time: $(((end_time - start_time) / 1000000)) ms" >&2
}

# Usage
time_function complex_operation arg1 arg2

Best Practices and Advanced Techniques

Script Structure

ksh
#!/bin/ksh
# Script description
# Author: Your Name
# Date: YYYY-MM-DD

# Strict mode
set -euo pipefail

# Global variables
typeset -r SCRIPT_NAME=${0##*/}
typeset -r SCRIPT_DIR=${0%/*}
typeset -r VERSION="1.0"

# Functions
function usage {
    cat << EOF
Usage: $SCRIPT_NAME [OPTIONS] [ARGUMENTS]

OPTIONS:
    -h, --help      Show this help
    -v, --version   Show version
    -d, --debug     Enable debug mode

EOF
}

function main {
    # Parse arguments
    while (($# > 0)); do
        case $1 in
            -h|--help)
                usage
                exit 0
                ;;
            -v|--version)
                print "$SCRIPT_NAME version $VERSION"
                exit 0
                ;;
            -d|--debug)
                set -x
                shift
                ;;
            -*)
                print "Unknown option: $1" >&2
                usage >&2
                exit 1
                ;;
            *)
                break
                ;;
        esac
    done
    
    # Main logic here
    print "Script execution completed"
}

# Error handling
function cleanup {
    # Cleanup code
    rm -f temp_files
}

trap cleanup EXIT

# Run main function
main "$@"

Error Handling Patterns

ksh
# Robust error handling
function safe_command {
    if ! command "$@"; then
        print "Error: Command failed: $*" >&2
        return 1
    fi
}

# Input validation
function validate_file {
    typeset file=$1
    
    if [[ ! -f $file ]]; then
        print "Error: File '$file' does not exist" >&2
        return 1
    fi
    
    if [[ ! -r $file ]]; then
        print "Error: File '$file' is not readable" >&2
        return 1
    fi
    
    return 0
}

# Retry mechanism
function retry_command {
    typeset -i attempts=3 delay=1
    typeset command="$*"
    
    for ((i = 1; i <= attempts; i++)); do
        if eval "$command"; then
            return 0
        fi
        
        if ((i < attempts)); then
            print "Attempt $i failed, retrying in $delay seconds..." >&2
            sleep $delay
            ((delay *= 2))
        fi
    done
    
    print "All $attempts attempts failed" >&2
    return 1
}

Security Considerations

ksh
# Input sanitization
function sanitize_input {
    typeset input=$1
    
    # Remove dangerous characters
    input=${input//[;&|`$()]/}
    
    # Validate against whitelist
    if [[ $input != +([a-zA-Z0-9_.-]) ]]; then
        print "Invalid input: $input" >&2
        return 1
    fi
    
    print "$input"
}

# Safe temporary files
function create_temp_file {
    typeset temp_file
    temp_file=$(mktemp) || {
        print "Failed to create temporary file" >&2
        return 1
    }
    
    # Set restrictive permissions
    chmod 600 "$temp_file"
    
    print "$temp_file"
}

# Secure PATH
export PATH="/usr/local/bin:/usr/bin:/bin"

# Use full paths for critical commands
/bin/rm -f "$temp_file"
/usr/bin/find "$directory" -name "*.tmp" -delete

The Korn Shell stands as a powerful and mature shell that bridges traditional Unix shell programming with modern scripting needs. Its combination of POSIX compliance, advanced programming features, and excellent performance makes it particularly valuable in enterprise environments where reliability and portability are paramount. While it may not have the extensive plugin ecosystems of modern shells like Zsh, ksh's built-in capabilities, mathematical functions, and robust scripting features make it an excellent choice for system administration, automation, and complex shell programming tasks.