Przejdź do treści

🐚 Zsh Differences Reference

Zsh (Z Shell) extends the Bourne shell with numerous features while maintaining compatibility. Understanding zsh-specific capabilities helps leverage its power while avoiding portability issues.


🎯 Major Zsh Features

Extended Globbing

Zsh provides powerful pattern matching beyond standard shell globbing.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Enable extended globbing
setopt extended_glob

# Recursive globbing
ls **/*.txt          # Find all .txt files recursively

# Negation patterns
ls ^*.log            # All files except .log files
ls *.txt~backup.*    # .txt files except those starting with backup

# Pattern exclusions
ls (*.txt|^backup*)  # .txt files but not starting with backup

# Approximate matching
ls (#a1)file.txt     # Files similar to file.txt (1 character difference)

# Numeric ranges
ls file<1-10>.txt    # file1.txt through file10.txt

# Qualifiers (file properties)
ls *(.)              # Regular files only
ls *(/)              # Directories only
ls *(@)              # Symlinks only
ls *(rwx)            # Files with specific permissions
ls *(m-1)            # Files modified within last day
ls *(^m+7)           # Files not modified in last 7 days

Arrays and Subscripts

Zsh offers advanced array handling with flexible indexing.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Array creation and manipulation
fruits=(apple banana cherry)
fruits+=("date")                    # Append element
fruits[5]="elderberry"              # Sparse array

# Array slicing
echo ${fruits[1,2]}                 # First two elements
echo ${fruits[2,-1]}                # From second to last
echo ${fruits[@]:1:2}               # POSIX-style slicing

# Array operations
echo ${#fruits}                     # Array length
echo ${fruits[(i)banana]}           # Index of element
echo ${fruits[(r)b*]}               # Element matching pattern

# Reverse array
echo ${fruits[::-1]}

# Unique elements
unique_fruits=(${(u)fruits})

# Sorted array
sorted_fruits=(${(o)fruits})

🔧 Parameter Expansion Extensions

Advanced Parameter Substitution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Case conversion
name="John Doe"
echo ${name:l}                      # john doe (lowercase)
echo ${name:u}                      # JOHN DOE (uppercase)

# Capitalization
echo ${name:c}                      # John doe (capitalize first)

# String manipulation
text="hello world"
echo ${text:s/world/universe/}      # hello universe (substitute)

# Length and substrings
echo ${#text}                       # 11 (length)
echo ${text:6:5}                    # world (substring)

# Split and join
csv="a,b,c"
array=(${(s:,:)csv})                # Split on comma
joined=${(j:,:)"$array"}            # Join with comma

# Remove duplicates
duplicated=(a b c a b)
unique=(${(u)duplicated})           # a b c

# Sort arrays
unsorted=(zebra alpha beta)
sorted=(${(o)unsorted})             # alpha beta zebra
reverse_sorted=(${(O)unsorted})     # zebra beta alpha

Parameter Flags

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Modifiers for parameter expansion
file="/home/user/documents/file.txt"

echo ${file:a}                      # Absolute path
echo ${file:A}                      # Resolved absolute path
echo ${file:h}                      # Head (directory) /home/user/documents
echo ${file:t}                      # Tail (filename) file.txt
echo ${file:r}                      # Root (without extension) /home/user/documents/file
echo ${file:e}                      # Extension txt

# Combining modifiers
echo ${file:h:t}                    # documents (parent directory name)
echo ${file:t:r}                    # file (basename without extension)

# Pattern-based modifications
path="/usr/local/bin/script.sh"
echo ${path:s/local/global/}        # /usr/global/bin/script.sh

🎨 Programming Constructs

Anonymous Functions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Anonymous functions with automatic cleanup
(){ echo "Temporary function"; } always { echo "Cleanup code"; }

# Function with try/catch-like behavior
try_this() {
    # Main code
} always {
    # Cleanup code (always executes)
    echo "Cleaning up..."
}

# Exception-like handling
might_fail() {
    if (( RANDOM % 2 )); then
        return 1
    fi
    echo "Success"
} always {
    if [[ $? -ne 0 ]]; then
        echo "Function failed, cleaning up..."
    fi
}

Mathematical Functions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Advanced mathematical operations
result=$(( sin(1.5) + cos(0.5) ))   # Trigonometric functions
result=$(( 2**10 ))                 # Exponentiation
result=$(( 10#0xFF ))               # Hexadecimal to decimal

# Floating point arithmetic
zmodload zsh/mathfunc
result=$(echo "sqrt(16)" | bc -l)   # Or use built-in math functions

# Complex number support
zmodload zsh/curses
# (Advanced mathematical operations)

🔍 Completion System

Programmable Completion

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Advanced completion with descriptions
_my_command() {
    local -a commands
    commands=(
        'start:start the service'
        'stop:stop the service'
        'restart:restart the service'
        'status:show service status'
    )

    _describe 'command' commands
}

compdef _my_command my_command

# File completion with patterns
_my_tool() {
    _arguments \
        '(-f --file)'{-f,--file}'[input file]:file:_files -g "*.txt"'
}

# Dynamic completion
_kubectl_resources() {
    local resources
    resources=($(kubectl api-resources -o name 2>/dev/null))
    _describe 'resource' resources
}

📊 Advanced I/O Features

Named Directories

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Named directory shortcuts
hash -d proj=/home/user/projects
cd ~proj/myproject                 # Go to /home/user/projects/myproject

# Automatic named directories
cd /very/long/path/to/project      # Automatically creates named directory
cd ~project                        # Later access

# List named directories
hash -d

Socket and Network Features

1
2
3
4
5
6
7
8
9
# TCP connections as file descriptors
ztcp hostname port
exec {fd}<>/dev/tcp/hostname/port
print -u$fd "GET / HTTP/1.0"
reply=$(<&$fd)
exec {fd}>&-

# UDP connections
ztcp -u hostname port

🛠️ Zsh-Specific Builtins

Enhanced Builtins

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# zcompile - compile zsh scripts for faster loading
zcompile ~/.zshrc

# zprof - profile shell performance
zmodload zsh/zprof
# ... run commands ...
zprof

# zpty - pseudo-terminal handling
zmodload zsh/zpty
zpty mysession ssh server
zpty -r mysession response
zpty -w mysession "command"

# zsh/net/tcp - network programming
zmodload zsh/net/tcp
ztcp server.com 80

Option Management

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Powerful option handling
setopt autocd autopushd pushdminus
unsetopt beep nomatch

# List all options
setopt

# Check specific options
if [[ -o autocd ]]; then
    echo "autocd is enabled"
fi

# Useful zsh options
setopt \
    extended_glob \          # Extended pattern matching
    glob_dots \              # Match dotfiles without ./
    inc_append_history \     # Append to history immediately
    share_history \          # Share history between sessions
    hist_ignore_dups \       # Ignore consecutive duplicates
    hist_reduce_blanks \     # Remove extra blanks from history
    correct \                # Spelling correction
    auto_cd \                # cd without typing cd
    auto_pushd \             # Push directories to stack automatically

🔄 Process Management

Job Control Extensions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Enhanced job control
jobs -l                      # List jobs with PIDs
jobs -r                      # Running jobs only
jobs -s                      # Stopped jobs only

# Job qualifiers
fg %?pattern                 # Foreground by pattern matching
bg %string                   # Background by string in command

# Process substitution with advanced features
diff =(sort file1) =(sort file2)  # Process substitution

Coprocesses

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# Advanced coprocess management
coproc sort_filter {
    while read line; do
        if [[ $line =~ ^[0-9]+$ ]]; then
            echo "NUMBER: $line"
        else
            echo "TEXT: $line"
        fi
    done
}

# Send data to coprocess
print -p "123"
print -p "hello"

# Read responses
read -p response
echo "Got: $response"

🎨 Prompt Customization

Advanced Prompt Escapes

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Rich prompt customization
PROMPT='%F{blue}%n%f@%F{green}%m%f:%F{yellow}%~%f %# '

# Prompt with git branch
autoload -Uz vcs_info
zstyle ':vcs_info:*' formats '%b'
precmd() { vcs_info }
RPROMPT='${vcs_info_msg_0_}'

# Asynchronous prompt updates
async_init
async_start_worker myworker -n
async_register_callback myworker prompt_callback

Right-side Prompts

1
2
3
4
5
6
7
8
9
# Right-aligned prompt elements
RPROMPT='%F{red}%D{%H:%M:%S}%f'

# Multiple prompt lines
PROMPT='%F{blue}%~%f
%# '

# Conditional prompts
PROMPT='%(?..%F{red}%?%f )%# '  # Show exit code if non-zero

⚠️ Zsh-Specific Features to Avoid for Portability

Non-Portable Constructs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# ❌ Zsh-specific features
array=(item1 item2 item3)          # Use in portable scripts
echo ${array[1]}                   # 1-indexed arrays
echo ${#array}                     # Array length syntax
echo ${array:#pattern}             # Array filtering

# ✅ Portable alternatives
# Use delimited strings:
ITEMS="item1:item2:item3"
IFS=':' read -ra items <<< "$ITEMS"
echo "${items[0]}"                 # 0-indexed in bash
echo "${#items[@]}"                # Portable array length

# ❌ Extended globbing
ls **/*.txt                        # Not POSIX
ls ^*.log                          # Negation patterns

# ✅ Portable alternatives
find . -name "*.txt"               # Recursive find
ls | grep -v '\.log$'              # Pattern exclusion

🧾 Version-Specific Features

Recent Zsh Features

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Zsh 5.0+ features
# Named references (similar to bash nameref)
typeset -n ref=original_var
ref="new value"  # Modifies original_var

# Improved parameter expansion
echo ${array[(b:2:i)pattern]}      # Backward search from index 2

# Enhanced completion matching
zstyle ':completion:*' matcher-list \
    '' 'm:{a-z\-}={A-Z\_}' 'r:[^[:alpha:]]||[[:alpha:]]=** r:|=* m:{a-z\-}={A-Z\_}' 'r:|?=** m:{a-z\-}={A-Z\_}'

# Multibyte character support
# Better Unicode handling in prompts and completions

Configuration Management

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# Zsh configuration files loading order
# 1. /etc/zshenv
# 2. ~/.zshenv
# 3. /etc/zprofile (login shells)
# 4. ~/.zprofile (login shells)
# 5. /etc/zshrc (interactive shells)
# 6. ~/.zshrc (interactive shells)
# 7. /etc/zlogin (login shells)
# 8. ~/.zlogin (login shells)

# Conditional configuration
if [[ -o interactive ]]; then
    # Interactive shell settings
    bindkey -e  # Emacs key bindings
fi

if [[ -o login ]]; then
    # Login shell settings
    source ~/.profile
fi

🧾 Summary Comparison

Feature Matrix

Feature Zsh Bash POSIX sh ksh
Arrays ✅ Advanced ✅ Basic ✅ Basic
Extended Globbing ✅ Rich Limited Limited
Parameter Expansion ✅ Extensive Good Basic Good
Completion System ✅ Advanced Good Basic
Anonymous Functions
Named Directories
Right Prompts
Spell Correction
Floating Point ✅ (modules)

When to Use Zsh Features

Use Zsh-specific features when: - Targeting interactive shell environments - Need advanced completion and customization - Want powerful pattern matching capabilities - Leveraging desktop/user environment scripts - Building sophisticated shell applications

Avoid Zsh-specific features when: - Writing portable system scripts - Targeting minimal environments - Need maximum compatibility - Following strict POSIX requirements - Developing production automation scripts


🧠 Best Practices

Zsh Usage Guidelines

  1. Explicit Shell Declaration: Use #!/usr/bin/env zsh for Zsh-specific scripts
  2. Feature Detection: Check for Zsh features before using them
  3. Module Loading: Use zmodload for advanced features
  4. Option Management: Document required Zsh options
  5. Completion Integration: Leverage Zsh's completion system
  6. Performance Considerations: Use zcompile for large scripts
  7. Debugging: Use zprof for performance profiling

Feature Detection

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Check if running in Zsh
if [ -n "$ZSH_VERSION" ]; then
    echo "Running in Zsh version $ZSH_VERSION"

    # Check for specific features
    if [[ ${ZSH_VERSION%%.*} -ge 5 ]]; then
        echo "Zsh 5.0+ features available"
    fi

    # Load modules safely
    if zmodload zsh/complist 2>/dev/null; then
        echo "Complist module loaded"
    fi
fi

# Conditional feature usage
enhanced_prompt() {
    if [ -n "$ZSH_VERSION" ]; then
        # Zsh-specific prompt
        PROMPT='%F{blue}%n%f@%F{green}%m%f:%F{yellow}%~%f %# '
    else
        # Basic prompt for other shells
        PS1='\u@\h:\w \$ '
    fi
}

🧾 See Also