1
0
mirror of https://github.com/zplug/zplug synced 2026-03-07 14:36:22 +01:00
zplug/.claude/skills/zsh-expert/SKILL.md

11 KiB

name description user-invocable argument-hint allowed-tools
zsh-expert Zsh scripting expert — explain Zsh-specific syntax, parameter expansions, array operations, and idioms in detail true <Zsh syntax or question> Read, Grep, Glob, WebSearch, WebFetch

Zsh Scripting Expert

Reference skill for Zsh syntax and idioms. Provides accurate, practical explanations when the user asks about Zsh-specific constructs.

Trigger

Automatically activate when:

  • The user asks about Zsh parameter expansions, array operations, glob qualifiers, or other Zsh-specific syntax
  • Code containing Zsh-specific constructs like ${(...)} or (( )) is being discussed
  • Questions like "How do I ... in Zsh" or "What does this Zsh syntax do"
  • Questions about differences between Bash and Zsh

Response Style

  • Respond in the same language the user uses (English or Japanese)
  • Start with a concise 1-2 line explanation of the syntax, then provide concrete examples
  • Highlight differences from Bash when relevant
  • Reference real examples from the zplug codebase with file paths and line numbers when applicable

Reference: Zsh Parameter Expansion

Basic Forms

Syntax Meaning
${var} Variable expansion
${var:-default} Use default if unset or empty
${var:=default} Assign default if unset or empty, then expand
${var:+alt} Use alt if set and non-empty
${var:?message} Error if unset or empty
${var-default} Use default if unset (empty is OK)
${+var} 1 if set, 0 if unset

String Manipulation

Syntax Meaning
${var#pattern} Remove shortest match from beginning
${var##pattern} Remove longest match from beginning
${var%pattern} Remove shortest match from end
${var%%pattern} Remove longest match from end
${var/pat/rep} Replace first match
${var//pat/rep} Replace all matches
${var/#pat/rep} Replace match at beginning
${var/%pat/rep} Replace match at end
${#var} String length (or element count for arrays)
${var:offset} Substring from offset
${var:offset:length} Substring from offset with length

Parameter Expansion Flags (Zsh-specific)

Used as ${(flags)var}. Multiple flags can be combined.

Flag Meaning Example
(U) Convert to uppercase ${(U)var}
(L) Convert to lowercase ${(L)var}
(C) Capitalize each word ${(C)var}
(s:sep:) Split on sep into array ${(s:.:)version}(1 0 3)
(j:sep:) Join array with sep ${(j:,:)array}a,b,c
(f) Split on newlines (same as (s:\n:)) ${(f)output}
(F) Join with newlines (same as (j:\n:)) ${(F)array}
(u) Remove duplicates (unique) ${(u)array}
(o) Sort ascending ${(o)array}
(O) Sort descending ${(O)array}
(on) Sort numerically ascending ${(on)array}
(M) Keep only matching elements ${(M)array:#pattern}
(k) Get associative array keys ${(k)assoc}
(v) Get associative array values ${(v)assoc}
(kv) Get keys and values interleaved ${(kv)assoc}
(t) Return variable type ${(t)var}scalar
(P) Indirect reference (name from value) ${(P)name}
(e) Expand $ variables in value ${(e)template}
(q) Add quoting ${(q)var}
(Q) Remove quoting ${(Q)var}
(w) Word count (with ${#}) ${(w)#var}
(S) Reverse shortest/longest match for #/% Substring match mode
(V) Make invisible characters visible ${(V)var}
(z) Tokenize using shell word splitting ${(z)cmdline}

Array Filtering

Syntax Meaning
${array:#pattern} Keep elements NOT matching pattern
${(M)array:#pattern} Keep ONLY elements matching pattern
${array[(i)value]} Index of first occurrence of value
${array[(I)value]} Index of last occurrence of value
${array[(r)pattern]} First element matching pattern
${array[(R)pattern]} Last element matching pattern

Reference: Array Operations

Basics

# Declaration
typeset -a arr=(one two three)

# Zsh is 1-indexed (Bash is 0-indexed)
echo $arr[1]          # one
echo $arr[-1]         # three (last element)

# Slicing
echo $arr[2,3]        # two three
echo $arr[2,-1]       # two three (from 2nd onward)

# Element count
echo $#arr            # 3
echo ${#arr[@]}       # 3

# Append
arr+=("four")
arr[5]="five"         # gaps filled with empty strings

# Delete (specific index)
arr[2]=()             # removes 2nd element and shifts

# Iterate all elements
for x in "${arr[@]}"; do echo $x; done

# Iterate with index
for i in {1..$#arr}; do echo "$i: $arr[$i]"; done

Associative Arrays

typeset -A hash
hash=(key1 val1 key2 val2)
# or
hash[key1]=val1

echo $hash[key1]        # val1
echo ${(k)hash}          # key1 key2 (keys)
echo ${(v)hash}          # val1 val2 (values)
echo ${(kv)hash}         # key1 val1 key2 val2

# Check key existence
(( ${+hash[key1]} )) && echo "exists"

# Element count
echo ${#hash}            # 2

Reference: Globbing

Extended Glob (setopt EXTENDED_GLOB)

Pattern Meaning
**/ Recursive directory match
(pat1|pat2) OR match
^pattern Negation match
pat~exclude Match pat but not exclude
# Zero or more repetitions (regex *)
## One or more repetitions (regex +)

Glob Qualifiers

Used as pattern(qualifier). Filter files by attributes.

Qualifier Meaning
. Regular files only
/ Directories only
@ Symbolic links only
* Executable files only
r / w / x Owner read/write/execute
R / W / X World read/write/execute
N NULL_GLOB (no error if no match)
D DOTGLOB (include hidden files)
on Sort by name
om Sort by modification time
oL Sort by file size
Om Reverse sort by modification time
[1] First match only
[1,5] First 5 matches
m-7 Modified within 7 days
L+1M Larger than 1MB
u:user: Owned by specified user
# Example: .zsh files under current dir, sorted by mtime
print -l **/*.zsh(.om)

# Example: regular files modified within 7 days
print -l *(m-7.)

Reference: Conditionals & Arithmetic

[[ ]] Conditional Expressions

[[ -n $var ]]          # Non-empty check
[[ -z $var ]]          # Empty check
[[ $a == $b ]]         # String equality
[[ $a != $b ]]         # String inequality
[[ $a =~ regex ]]      # Regex match (results in MATCH, match)
[[ $a == pattern ]]    # Glob pattern match
[[ -e $file ]]         # File exists
[[ -d $dir ]]          # Is a directory
[[ -f $file ]]         # Is a regular file
[[ -L $file ]]         # Is a symbolic link
[[ -x $file ]]         # Is executable

Zsh-specific: == supports glob pattern matching inside [[ ]]. PCRE is available with =~ when setopt RE_MATCH_PCRE is set.

(( )) Arithmetic Expressions

(( x = 5 + 3 ))        # Assignment
(( x++ ))               # Increment
(( x > 0 )) && echo positive
(( result = a > b ? a : b ))  # Ternary operator

Reference: Zsh-Specific Builtins

Command Meaning
typeset / declare Variable declaration (-a array, -A assoc array, -i integer, -r readonly, -g global)
local Function-local variable (equivalent to typeset)
autoload Declare lazy-loaded function
autoload -Uz func -U suppress alias expansion, -z zsh-style
zmodload Load Zsh modules
zstyle Context-based configuration
compdef Bind completion function
add-zsh-hook Add hook function to precmd/preexec etc.
emulate -L zsh Force Zsh emulation within a function
setopt / unsetopt Set/unset shell options
print Enhanced echo (-P prompt expansion, -l one per line, -r no escapes)
read -q Y/n prompt, -s silent input, -A read into array

Reference: Useful Options

Option Meaning
LOCAL_OPTIONS Restore options set within a function on return
LOCAL_TRAPS Restore traps set within a function on return
EXTENDED_GLOB Enable extended globbing
NULL_GLOB No error when glob has no match
KSH_ARRAYS Make arrays 0-indexed (rarely used)
WARN_CREATE_GLOBAL Warn on implicit global variable creation in functions
ERR_EXIT Exit immediately on command failure
PIPE_FAIL Detect failures within pipelines
NO_UNSET Error on referencing unset variables

Reference: Hooks & Traps

# precmd: runs just before each prompt display
add-zsh-hook precmd my_precmd_func

# preexec: runs just before command execution (arg: command string)
add-zsh-hook preexec my_preexec_func

# chpwd: runs on directory change
add-zsh-hook chpwd my_chpwd_func

# zshexit: runs on shell exit
add-zsh-hook zshexit my_cleanup_func

# TRAPINT: Ctrl+C handler
TRAPINT() { print "interrupted"; return 128+2; }

# TRAPERR: error handler
TRAPERR() { print "error: $?" >&2; }

# TRAPZERR: non-zero exit handler (equivalent to TRAPERR)

Reference: Anonymous Functions

# Immediately-invoked function (creates scope)
() {
    local tmp="scoped"
    echo $tmp
}

# With arguments
() {
    echo "arg1=$1 arg2=$2"
} "hello" "world"

Reference: Key Differences from Bash

Feature Bash Zsh
Array indexing 0-indexed 1-indexed
Array access ${arr[0]} $arr[1] or ${arr[1]}
Bare $arr First element All elements (same as ${arr[@]})
Associative array declaration declare -A typeset -A
Word splitting On by default Off by default
Glob qualifiers None (.om) and many more
Parameter expansion flags None ${(s:.:)var} and many more
[[ $x == pattern ]] Glob match Glob match
=~ regex ERE (BASH_REMATCH) ERE (MATCH, match)
print command Not built-in Built-in
emulate Not available Available
Function scoping Dynamic Dynamic (typeset for local)
Anonymous functions Not available () { ... }
Hook mechanism Not available add-zsh-hook

Reference: ZLE (Zsh Line Editor)

# Custom widget
my-widget() {
    BUFFER="modified"
    CURSOR=$#BUFFER
}
zle -N my-widget
bindkey '^X^M' my-widget

# Key variables
# BUFFER  — current input line
# CURSOR  — cursor position
# LBUFFER — text left of cursor
# RBUFFER — text right of cursor
# WIDGET  — name of currently executing widget

Answer Guidelines

  1. Start with a concise 1-2 line explanation of the syntax in question
  2. Provide concrete code examples (minimal and runnable)
  3. Note any gotchas or common pitfalls
  4. Reference real usage in the zplug codebase when applicable, using base/path/file.zsh:NN format
  5. For users coming from Bash, explicitly highlight the differences
  6. List related syntax or flags under a "See also" section when relevant