string-manipulation-mastery

安装量: 55
排名: #13433

安装

npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill string-manipulation-mastery

CRITICAL GUIDELINES Windows File Path Requirements

MANDATORY: Always Use Backslashes on Windows for File Paths

When using Edit or Write tools on Windows, you MUST use backslashes () in file paths, NOT forward slashes (/).

Bash String Manipulation Mastery (2025) Overview

Comprehensive guide to string manipulation in bash using parameter expansion, pattern matching, regular expressions, and built-in transformations. Master these techniques to avoid spawning external processes like sed, awk, or cut for simple operations.

Parameter Expansion Basics String Length

!/usr/bin/env bash

set -euo pipefail

str="Hello, World!"

Get length

echo "${#str}" # 13

Length of array element

arr=("short" "much longer string") echo "${#arr[0]}" # 5 echo "${#arr[1]}" # 18

Number of array elements (not string length)

echo "${#arr[@]}" # 2

Substring Extraction

!/usr/bin/env bash

set -euo pipefail

str="Hello, World!"

${var:offset} - from offset to end

echo "${str:7}" # World!

${var:offset:length} - from offset, length chars

echo "${str:0:5}" # Hello echo "${str:7:5}" # World

Negative offset (from end) - note the space or parentheses

echo "${str: -6}" # World! echo "${str:(-6)}" # World! echo "${str: -6:5}" # World

Last N characters

last_n() { local str="$1" n="$2" echo "${str: -$n}" } last_n "Hello" 3 # llo

Extract between positions

between() { local str="$1" start="$2" end="$3" echo "${str:start:$((end - start))}" } between "0123456789" 3 7 # 3456

Default Values

!/usr/bin/env bash

set -euo pipefail

${var:-default} - use default if unset or empty

name="${1:-Anonymous}" echo "Hello, $name"

${var:=default} - assign default if unset or empty

"${CONFIG_FILE:=/etc/app.conf}"

${var:+alternate} - use alternate if var IS set

debug_flag="${DEBUG:+--verbose}"

${var:?error} - exit with error if unset or empty

"${REQUIRED_VAR:?REQUIRED_VAR must be set}"

Without colon - only checks if unset (empty is OK)

${var-default}, ${var=default}, ${var+alt}, ${var?err}

Practical example: config with defaults

setup_config() { : "${DB_HOST:=localhost}" : "${DB_PORT:=5432}" : "${DB_NAME:=myapp}" : "${DB_USER:=postgres}" }

Indirect Expansion

!/usr/bin/env bash

set -euo pipefail

${!var} - indirect reference

config_host="server.example.com" config_port="8080"

key="config_host" echo "${!key}" # server.example.com

Iterate over related variables

for suffix in host port; do var="config_$suffix" echo "$suffix = ${!var}" done

Get all variable names matching pattern

${!prefix@} or ${!prefix*}

for var in "${!config_@}"; do echo "$var = ${!var}" done

Array indirection

arr=(a b c d e) idx=2 echo "${arr[$idx]}" # c

Indirect array reference (Bash 4.3+ nameref)

get_array_element() { local -n arr_ref="$1" local idx="$2" echo "${arr_ref[$idx]}" } get_array_element arr 3 # d

Pattern Matching Prefix Removal

!/usr/bin/env bash

set -euo pipefail

path="/home/user/documents/file.tar.gz"

${var#pattern} - remove shortest prefix match

echo "${path#*/}" # home/user/documents/file.tar.gz

${var##pattern} - remove longest prefix match

echo "${path##*/}" # file.tar.gz (basename)

Remove extension

filename="archive.tar.gz" echo "${filename#.}" # tar.gz (first . onwards) echo "${filename##.}" # gz (last extension only)

Remove prefix string

url="https://example.com/path" echo "${url#https://}" # example.com/path

Practical: Get file extension

get_extension() { local file="$1" echo "${file##*.}" }

Practical: Strip leading zeros

strip_leading_zeros() { local num="$1" echo "${num#"${num%%[!0]*}"}" } strip_leading_zeros "000123" # 123

Suffix Removal

!/usr/bin/env bash

set -euo pipefail

path="/home/user/documents/file.tar.gz"

${var%pattern} - remove shortest suffix match

echo "${path%/*}" # /home/user/documents (dirname)

${var%%pattern} - remove longest suffix match

echo "${path%%/*}" # (empty - removes everything)

Remove extension

filename="archive.tar.gz" echo "${filename%.}" # archive.tar echo "${filename%%.}" # archive

Practical: Get directory

dirname="${path%/*}"

Practical: Remove file extension

basename="${path##/}" name_without_ext="${basename%.}"

Combined: Change extension

change_extension() { local file="$1" new_ext="$2" echo "${file%.*}.$new_ext" } change_extension "doc.txt" "md" # doc.md

Pattern Substitution

!/usr/bin/env bash

set -euo pipefail

str="hello hello hello"

${var/pattern/replacement} - replace first match

echo "${str/hello/hi}" # hi hello hello

${var//pattern/replacement} - replace all matches

echo "${str//hello/hi}" # hi hi hi

${var/#pattern/replacement} - replace if at start

echo "${str/#hello/hi}" # hi hello hello

${var/%pattern/replacement} - replace if at end

echo "${str/%hello/goodbye}" # hello hello goodbye

Delete pattern (empty replacement)

echo "${str//hello/}" # " " (just spaces)

Practical: Sanitize filename

sanitize_filename() { local name="$1" # Replace spaces with underscores name="${name// /}" # Remove special characters name="${name//[^a-zA-Z0-9.-]/}" echo "$name" } sanitize_filename "My File (2024).txt" # My_File_2024.txt

Practical: Path manipulation

normalize_path() { local path="$1" # Remove double slashes while [[ "$path" == // ]]; do path="${path//\/\//\/}" done # Remove trailing slash echo "${path%/}" }

Case Transformation Basic Case Changes

!/usr/bin/env bash

set -euo pipefail

str="Hello World"

Lowercase first character

echo "${str,}" # hello World

Lowercase all

echo "${str,,}" # hello world

Uppercase first character

echo "${str^}" # Hello World (already uppercase)

str2="hello world" echo "${str2^}" # Hello world

Uppercase all

echo "${str,,}" # hello world echo "${str2^^}" # HELLO WORLD

Toggle case (Bash 4.4+)

echo "${str~~}" # hELLO wORLD

Pattern-Based Case Changes

!/usr/bin/env bash

set -euo pipefail

str="hello world"

Uppercase only matching pattern

echo "${str^^[aeiou]}" # hEllO wOrld

Lowercase only matching pattern

str2="HELLO WORLD" echo "${str2,,[AEIOU]}" # HeLLo WoRLD

Practical: Title case

title_case() { local str="$1" local result="" local capitalize=true

for ((i=0; i<${#str}; i++)); do
    local char="${str:$i:1}"
    if [[ "$char" == " " ]]; then
        result+="$char"
        capitalize=true
    elif $capitalize; then
        result+="${char^}"
        capitalize=false
    else
        result+="${char,}"
    fi
done

echo "$result"

} title_case "hello WORLD from BASH" # Hello World From Bash

Regular Expressions Bash Regex Matching

!/usr/bin/env bash

set -euo pipefail

=~ operator for regex matching

str="Hello World 123"

if [[ "$str" =~ ^Hello ]]; then echo "Starts with Hello" fi

if [[ "$str" =~ [0-9]+ ]]; then echo "Contains numbers" fi

Capture groups with BASH_REMATCH

email="user@example.com" if [[ "$email" =~ ^([^@]+)@(.+)$ ]]; then echo "User: ${BASH_REMATCH[1]}" # user echo "Domain: ${BASH_REMATCH[2]}" # example.com echo "Full match: ${BASH_REMATCH[0]}" # user@example.com fi

Store regex in variable (avoids quoting issues)

pattern='^[0-9]{4}-[0-9]{2}-[0-9]{2}$' date="2024-03-15" if [[ "$date" =~ $pattern ]]; then echo "Valid date format" fi

Multiple capture groups

log_line='2024-03-15 10:30:45 ERROR Connection failed' pattern='^([0-9-]+) ([0-9:]+) ([A-Z]+) (.+)$' if [[ "$log_line" =~ $pattern ]]; then date="${BASH_REMATCH[1]}" time="${BASH_REMATCH[2]}" level="${BASH_REMATCH[3]}" message="${BASH_REMATCH[4]}" fi

Practical Regex Patterns

!/usr/bin/env bash

set -euo pipefail

Email validation

is_valid_email() { local email="$1" local pattern='^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$' [[ "$email" =~ $pattern ]] }

IP address validation

is_valid_ip() { local ip="$1" local octet='(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' local pattern="^${octet}.${octet}.${octet}.${octet}$" [[ "$ip" =~ $pattern ]] }

URL parsing

parse_url() { local url="$1" local pattern='^(https?|ftp)://([^/:]+)(:([0-9]+))?(/.*)?$'

if [[ "$url" =~ $pattern ]]; then
    echo "Protocol: ${BASH_REMATCH[1]}"
    echo "Host: ${BASH_REMATCH[2]}"
    echo "Port: ${BASH_REMATCH[4]:-default}"
    echo "Path: ${BASH_REMATCH[5]:-/}"
else
    echo "Invalid URL" >&2
    return 1
fi

}

Semantic version parsing

parse_semver() { local version="$1" local pattern='^v?([0-9]+).([0-9]+).([0-9]+)(-([a-zA-Z0-9.-]+))?(+([a-zA-Z0-9.-]+))?$'

if [[ "$version" =~ $pattern ]]; then
    echo "Major: ${BASH_REMATCH[1]}"
    echo "Minor: ${BASH_REMATCH[2]}"
    echo "Patch: ${BASH_REMATCH[3]}"
    echo "Prerelease: ${BASH_REMATCH[5]:-none}"
    echo "Build: ${BASH_REMATCH[7]:-none}"
fi

}

String Splitting and Joining Split String to Array

!/usr/bin/env bash

set -euo pipefail

Using IFS and read

str="one,two,three,four"

IFS=',' read -ra arr <<< "$str" echo "${arr[0]}" # one echo "${arr[2]}" # three

Multi-character delimiter (using parameter expansion)

str="one||two||three" arr=() while [[ "$str" == "||" ]]; do arr+=("${str%%||}") str="${str#||}" done arr+=("$str")

Using mapfile (newline-delimited)

mapfile -t lines <<< "$(echo -e "line1\nline2\nline3")"

Split on any whitespace

str="one two three" read -ra arr <<< "$str" # IFS defaults to whitespace

Join Array to String

!/usr/bin/env bash

set -euo pipefail

arr=("one" "two" "three" "four")

Join with delimiter using IFS

join_by() { local IFS="$1" shift echo "$*" } join_by ',' "${arr[@]}" # one,two,three,four join_by ' | ' "${arr[@]}" # one | two | three | four

Alternative using printf

join_array() { local delim="$1" shift local first="$1" shift printf '%s' "$first" "${@/#/$delim}" } join_array ',' "${arr[@]}"

Join with custom format

printf '"%s" ' "${arr[@]}" # "one" "two" "three" "four" printf '%s\n' "${arr[@]}" # One per line

Text Processing Without External Commands Trim Whitespace

!/usr/bin/env bash

set -euo pipefail

Trim leading whitespace

trim_leading() { local str="$1" echo "${str#"${str%%[![:space:]]*}"}" }

Trim trailing whitespace

trim_trailing() { local str="$1" echo "${str%"${str##*[![:space:]]}"}" }

Trim both

trim() { local str="$1" str="${str#"${str%%[![:space:]]}"}" str="${str%"${str##[![:space:]]}"}" echo "$str" }

Extended pattern matching version (requires shopt -s extglob)

trim_extglob() { shopt -s extglob local str="$1" str="${str##+([[:space:]])}" str="${str%%+([[:space:]])}" echo "$str" }

str=" hello world " trim "$str" # "hello world"

String Repetition

!/usr/bin/env bash

set -euo pipefail

Repeat string N times

repeat() { local str="$1" local n="$2" local result=""

for ((i=0; i<n; i++)); do
    result+="$str"
done

echo "$result"

}

repeat "ab" 5 # ababababab

Using printf

repeat_printf() { local str="$1" local n="$2" printf '%s' $(printf '%.0s'"$str" $(seq 1 "$n")) }

Create separator line

separator() { local char="${1:--}" local width="${2:-80}" printf '%*s\n' "$width" '' | tr ' ' "$char" }

separator "=" 40 # ========================================

Character Replacement

!/usr/bin/env bash

set -euo pipefail

str="hello world"

Using tr-like replacement via expansion

Replace all 'l' with 'L'

echo "${str//l/L}" # heLLo worLd

Delete characters

echo "${str//o/}" # hell wrld

Translate character by character

translate() { local str="$1" local from="$2" local to="$3"

for ((i=0; i<${#from}; i++)); do
    str="${str//${from:$i:1}/${to:$i:1}}"
done

echo "$str"

}

translate "hello" "el" "ip" # hippo

Padding and Alignment

!/usr/bin/env bash

set -euo pipefail

Right pad to width

pad_right() { local str="$1" local width="$2" local char="${3:- }" printf "%-${width}s" "$str" | tr ' ' "$char" }

Left pad to width

pad_left() { local str="$1" local width="$2" local char="${3:- }" printf "%${width}s" "$str" | tr ' ' "$char" }

Center align

center() { local str="$1" local width="$2" local len=${#str} local padding=$(( (width - len) / 2 ))

printf "%*s%s%*s" $padding "" "$str" $((width - len - padding)) ""

}

Zero-pad numbers

zero_pad() { local num="$1" local width="$2" printf "%0${width}d" "$num" }

zero_pad 42 5 # 00042

Format table

print_table_row() { printf "| %-20s | %10s | %-15s |\n" "$1" "$2" "$3" }

print_table_row "Name" "Age" "City" print_table_row "Alice" "30" "New York"

Extended Globbing Enable and Use

!/usr/bin/env bash

set -euo pipefail shopt -s extglob

Extended patterns:

?(pattern) - 0 or 1 occurrence

*(pattern) - 0 or more occurrences

+(pattern) - 1 or more occurrences

@(pattern) - exactly 1 occurrence

!(pattern) - anything except pattern

Match files

ls .@(jpg|png|gif) # Images only ls !(.bak|*.tmp) # Exclude backup/temp files ls +([0-9]).txt # Files starting with digits

String manipulation

str=" hello world "

Remove leading whitespace

echo "${str##+([[:space:]])}" # "hello world "

Remove all whitespace

echo "${str//+([[:space:]])/ }" # " hello world "

Remove multiple extensions

file="archive.tar.gz.bak" echo "${file%.@(tar|gz|bak)*}" # archive

Match alternatives

case "$response" in @(yes|y|Y|YES)) echo "Affirmative" ;; @(no|n|N|NO)) echo "Negative" ;; esac

Practical Extended Glob Patterns

!/usr/bin/env bash

set -euo pipefail shopt -s extglob

Clean backup files

rm -f *.@(bak|backup|orig|~)

Find source files only

ls *.@(c|cpp|h|hpp|cc)

Exclude certain patterns

for file in !(test_|_).py; do process "$file" done

Match complex version strings

version_pattern='+([0-9]).+([0-9]).+([0-9])?(-+([a-z0-9]))' if [[ "$version" == $version_pattern ]]; then echo "Valid version" fi

Remove redundant characters

clean_string() { local str="$1" # Remove repeated spaces echo "${str//+([[:space:]])/ }" }

Match optional parts

file_pattern='*.@(test|spec)?.@(js|ts)'

Matches: file.js, file.ts, file.test.js, file.spec.ts, etc.

Bash 5.3+ String Features In-Shell Substitution for Strings

!/usr/bin/env bash

Requires Bash 5.3+

set -euo pipefail

No-fork string operations

result=${ echo "${str^^}"; } # Uppercase without subshell

REPLY syntax for string building

build_path() { local parts=("$@") REPLY=""

for part in "${parts[@]}"; do
    ${| REPLY+="${REPLY:+/}$part"; }
done

}

Efficient string accumulation

accumulate() { local -n result="$1" shift

for item in "$@"; do
    ${| result+="$item"; }
done

}

Performance Tips Avoid Subshells for Simple Operations

!/usr/bin/env bash

set -euo pipefail

str="hello world"

✗ SLOW - spawns external process

basename=$(basename "$path") dirname=$(dirname "$path") upper=$(echo "$str" | tr 'a-z' 'A-Z') len=$(echo -n "$str" | wc -c)

✓ FAST - pure bash

basename="${path##/}" dirname="${path%/}" upper="${str^^}" len="${#str}"

Batch String Operations

!/usr/bin/env bash

set -euo pipefail

✗ SLOW - multiple expansions

str="$input" str="${str// / }" str="${str#"${str%%[![:space:]]}"}" str="${str%"${str##[![:space:]]}"}" str="${str,,}"

✓ BETTER - single function call

normalize_string() { local str="$1" str="${str// / }" str="${str#"${str%%[![:space:]]}"}" str="${str%"${str##[![:space:]]}"}" echo "${str,,}" } result=$(normalize_string "$input")

Resources Bash Reference - Shell Parameter Expansion Bash Reference - Pattern Matching BashFAQ/100 - String manipulation Bash Hackers - Parameter Expansion

Master bash string manipulation to write efficient scripts without external dependencies.

返回排行榜