Jacky's blog
首页
  • Android
  • Web
  • Server
  • Python
  • iOS
  • Java
  • Vue
  • 计算机基础
  • AI
  • 全部工具
  • CLI 工具
  • 编辑器
  • 开发工具
  • 构建工具
  • 版本控制
  • 调试工具
  • 网络工具
  • 个人成长
  • 博客
  • 分类
  • 标签
  • 归档
收藏
GitHub (opens new window)

Jack Yang

编程; 随笔
首页
  • Android
  • Web
  • Server
  • Python
  • iOS
  • Java
  • Vue
  • 计算机基础
  • AI
  • 全部工具
  • CLI 工具
  • 编辑器
  • 开发工具
  • 构建工具
  • 版本控制
  • 调试工具
  • 网络工具
  • 个人成长
  • 博客
  • 分类
  • 标签
  • 归档
收藏
GitHub (opens new window)
  • 计算机基础
  • 计算机基础

  • 网络

  • 操作系统

  • Shell
    • Shell 学习与使用导航
    • shell 入门指南
    • Shell 执行模型与环境加载
    • Shell 错误处理、调试与资源清理
    • Shell 常用命令速查手册
    • Shell 代码片段集合
      • 📋 目录
      • pyenv
      • v2ray 安装脚本学习
      • genrandomstring
      • 文件操作
        • 文件备份
        • 批量文件重命名
        • 目录清理
      • 系统信息获取
        • 系统版本检测
        • 磁盘空间检查
      • 网络和进程管理
        • 端口检查
        • 进程管理
      • 实用工具函数
        • 日志记录
        • 颜色输出
        • 进度条显示
      • 数据处理
        • CSV 文件处理
        • 文本搜索和替换
      • 最佳实践
        • 脚本头部模板
        • 错误处理模板
        • 使用说明
        • 注意事项
  • 安全

  • 设计模式

  • cs
  • shell
Jacky
2024-10-15
目录

Shell 代码片段集合

默认 Bash 3.2+,外部工具按 macOS/BSD 与 GNU/Linux 差异标注。随机串、CSV 和批量文本操作使用 Python 3.8+;先 command -v python3 检查,不假设系统预装。函数正常返回 0,失败返回非零(端口查询 1 表示未发现);诊断写 stderr。复制函数定义后单独调用,示例路径需按实际替换。

副作用约定:重命名、文本替换默认只预览,最后传 --apply 才写入;备份创建新文件;清理函数会删除匹配项,先使用对应的 find 查询;发送信号和监控均需人工确认目标。所有关键写入显式检查状态,不依赖 set -e。

# 📋 目录

  • pyenv 脚本
  • 随机字符串生成
  • 文件操作
  • 系统信息获取
  • 网络和进程管理
  • 实用工具函数
  • 数据处理

# pyenv

#!/usr/bin/env bash
set -e
[ -n "${PYENV_DEBUG:-}" ] && set -x

program="${0##*/}"

export PYENV_ROOT="$HOME/.pyenv"
exec "/usr/local/opt/pyenv/bin/pyenv" exec "$program" "$@"
1
2
3
4
5
6
7
8

这是一个 Bash 脚本, 用于在 Pyenv 环境中执行 Python 程序。以下是对脚本的解释:

  • #!/usr/bin/env bash: 这是一个 Shebang 行, 它告诉操作系统使用 Bash 来执行这个脚本
  • set -e: 这个命令将在脚本中启用"strict mode", 在适用上下文遇非零状态时退出;if、&&/|| 等有例外,见 错误处理指南
  • [ -n "${PYENV_DEBUG:-}" ] && set -x: 如果存在名为 PYENV_DEBUG 的环境变量并且其值非空, 则启用调试模式, 该模式会输出每个命令的执行
  • program="${0##\*/}": 这一行提取了脚本文件的名称, 将其存储在变量 program 中
  • export PYENV_ROOT="$HOME/.pyenv": 这一行设置了 PYENV_ROOT 环境变量, 指定 Pyenv 的根目录
  • exec "/usr/local/opt/pyenv/bin/pyenv" exec "$program" "$@": 这是实际执行 Python 程序的命令。它使用 pyenv 工具来执行 Python 程序, "表示要执行的程序的名称@"表示传递给脚本的所有参数将传递给 Python 程序

总之, 这个脚本的目的是在 Pyenv 环境中执行 Python 程序, 它设置了一些环境变量, 并使用 pyenv 来确保 Python 程序在正确的环境中运行。如果你需要在 Pyenv 中运行 Python 程序, 并且希望通过脚本来管理它, 这个脚本可以派上用场

# v2ray 安装脚本学习

原笔记标识:install-install-v2ray_study_shell_cache。当前库中未附脚本正文,保留此检索线索;尚不足以作为可执行安装指南。补回原脚本后再按参数解析、下载校验、提权与失败清理逐段解读。

# gen_random_string

gen_random_string() {
    python3 - "${1:-16}" <<'PYCODE'
import secrets, string, sys
try:
    length = int(sys.argv[1])
    if not sys.argv[1].isascii() or not sys.argv[1].isdigit() or not 1 <= length <= 1048576:
        raise ValueError('长度应为 1..1048576 的十进制整数')
    alphabet = string.ascii_letters + string.digits
    print(''.join(secrets.choice(alphabet) for _ in range(length)))
except ValueError as exc:
    print(exc, file=sys.stderr)
    sys.exit(2)
PYCODE
}

# 直接使用短路操作
gen_random_string "$@" || { echo "Failed to generate random string."; exit 1; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

旧实现 LC_ALL=C tr -dc 'a-zA-Z0-9' </dev/urandom | head -c N 的知识点仍保留:head 提前退出可能使 tr 收到 SIGPIPE,在 pipefail 下整个管道返回 141;使用 func || handler 还可能抑制函数内部 errexit,不能据此证明普通调用安全。新版用有限次随机选择,避免截断无限输入。

  • LC_ALL=C:设置字符集为 C locale(标准 ASCII 字符集),确保字符处理的行为在不同系统下保持一致
  • tr -dc 'a-zA-Z0-9':从 /dev/urandom 读取随机字节,并删除所有不在 a-zA-Z0-9 范围内的字符

# 文件操作

# 文件备份

# 安全备份文件
backup_file() {
    local file="$1" backup_dir="${2:-./backup}" target
    [ -f "$file" ] || { printf '不是普通文件: %s\n' "$file" >&2; return 1; }
    mkdir -p "$backup_dir" || return 1
    target=$(mktemp "$backup_dir/${file##*/}.bak.XXXXXX") || return 1
    if cp "$file" "$target"; then
        printf '备份完成: %s\n' "$target"
    else
        rm -f "$target"
        return 1
    fi
}

# 使用示例
backup_file "/etc/nginx/nginx.conf" "/tmp/backup"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 批量文件重命名

# 批量重命名文件
batch_rename() {
    python3 - "$@" <<'PYCODE'
import os, pathlib, sys
try:
    if len(sys.argv) not in (3, 4, 5):
        raise ValueError('用法: batch_rename <字面原文> <替换文本> [目录] [--apply]')
    search, replacement = sys.argv[1:3]
    directory = pathlib.Path(sys.argv[3] if len(sys.argv) >= 4 else '.')
    apply = len(sys.argv) == 5 and sys.argv[4] == '--apply'
    if len(sys.argv) == 5 and not apply:
        raise ValueError('未知执行选项')
    if not search or '/' in replacement or '\0' in replacement:
        raise ValueError('原文不能为空,替换文本不能含路径分隔符或 NUL')
    plan = []
    for src in sorted(directory.iterdir()):
        if src.is_symlink() or not src.is_file():
            continue
        name = src.name.replace(search, replacement)
        if name == src.name:
            continue
        if name in ('', '.', '..'):
            raise ValueError('非法目标名称')
        dest = src.with_name(name)
        plan.append((src, dest))
    targets = [str(dest) for _, dest in plan]
    if len(targets) != len(set(targets)):
        raise ValueError('多个来源映射到同一目标')
    for src, dest in plan:
        if os.path.lexists(dest):
            raise FileExistsError(f'目标已存在: {dest!s}')
    for src, dest in plan:
        print(f'{str(src)!r} -> {str(dest)!r}', flush=True)
        if apply:
            # 同目录普通文件:目标排他创建,遇并发冲突也不覆盖;失败立即停止。
            os.link(src, dest)
            os.unlink(src)
except (OSError, ValueError) as exc:
    print(f'重命名失败: {exc}', file=sys.stderr)
    sys.exit(1)
PYCODE
}

# 使用示例:将 .txt 改为 .bak
batch_rename ".txt" ".bak" "/path/to/files"          # 预览全部映射并检查冲突
batch_rename ".txt" ".bak" "/path/to/files" --apply  # 确认后执行
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

这里的替换为字面量、全部出现位置,旧 ${basename//$pattern/$replacement} 则把 pattern 当 Shell 模式。只处理指定目录的普通文件(含隐藏文件、排除符号链接),不递归。为避免 mv 默认覆盖,使用同目录硬链接再删除原目录项;文件系统必须支持硬链接。批量操作不保证整体原子性:中途失败会留下已完成项;若 unlink 失败可能保留两个名称,需按计划核对后恢复。不要在其他进程同时修改来源时运行。

备份的随机后缀替代秒级时间戳,重复调用不会覆盖;mkdir、mktemp、cp 任一步失败均非零,不输出“备份完成”。只保证内容备份,不保证跨平台完整保留 ACL/扩展属性。

# 目录清理

# 清理空目录
cleanup_empty_dirs() {
    local dir="${1:-.}"
    find "$dir" -depth -mindepth 1 -type d -empty -delete || return 1
    printf '%s\n' '空目录清理完成'
}

# 清理临时文件
cleanup_temp_files() {
    local dir="${1:-.}"
    find "$dir" -type f \( -name '*.tmp' -o -name '*.temp' -o -name '*~' \) -print
    # 确认上面匹配列表后再执行;find -exec 保留空格、换行等文件名边界。
    find "$dir" -type f \( -name '*.tmp' -o -name '*.temp' -o -name '*~' \) -exec rm -f {} +
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 系统信息获取

清理前单独执行同样的 find 条件并去掉 -delete/-exec rm ... 查看结果;调用上述函数即表示执行清理。空目录函数排除起始目录本身;临时文件函数只删普通文件,括号确保 -type f 约束全部名称条件。不要通过默认 xargs 或按换行 read 传递任意路径。

# 系统版本检测

# 检测操作系统类型
detect_os() {
    if [[ "$OSTYPE" == "linux-gnu"* ]]; then
        echo "Linux"
    elif [[ "$OSTYPE" == "darwin"* ]]; then
        echo "macOS"
    elif [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]]; then
        echo "Windows"
    else
        echo "Unknown: $OSTYPE"
    fi
}

# 获取系统详细信息
get_system_info() {
    echo "=== 系统信息 ==="
    echo "操作系统: $(detect_os)"
    echo "内核版本: $(uname -r)"
    echo "架构: $(uname -m)"
    echo "主机名: $(hostname)"
    echo "用户: $(whoami)"
    echo "Shell: $SHELL"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 磁盘空间检查

# 检查磁盘使用情况
check_disk_usage() {
    local threshold="${1:-80}"  # 默认阈值 80%

    local data
    [[ "$threshold" =~ ^[0-9]+$ ]] && [ "$threshold" -le 100 ] || return 2
    data=$(df -Pk) || return 1
    printf '%s\n' "$data" | awk -v threshold="$threshold" '
    NR>1 {
        gsub(/%/, "", $5)
        if ($5 > threshold) {
            print "警告: " $1 " 使用率 " $5 "% 超过阈值 " threshold "%"
        }
    }'
}

# 查找大文件
find_large_files() {
    local size="${1:-100M}" dir="${2:-.}"
    # 原 find -size +100M 在 BSD/GNU 上后缀不同;统一换算为字节 c。
    python3 - "$size" "$dir" <<'PYCODE'
import os, pathlib, re, sys
try:
    match = re.fullmatch(r'([0-9]+)([ckMG]?)', sys.argv[1])
    if not match:
        raise ValueError('大小格式: 数字 + c/k/M/G;无单位按字节')
    units = {'': 1, 'c': 1, 'k': 1024, 'M': 1024**2, 'G': 1024**3}
    threshold = int(match[1]) * units[match[2]]
    root = pathlib.Path(sys.argv[2])
    if not root.is_dir():
        raise ValueError('目录不存在')
    results = []
    def walk_error(exc):
        raise exc
    for parent, _, names in os.walk(root, onerror=walk_error):
        for name in names:
            path = pathlib.Path(parent) / name
            if path.is_symlink() or not path.is_file():
                continue
            size = path.stat().st_size
            if size > threshold:
                results.append((size, str(path)))
    for size, path in sorted(results, reverse=True):
        print(f'{size} bytes\t{path!r}')
except (OSError, ValueError) as exc:
    print(exc, file=sys.stderr)
    sys.exit(1)
PYCODE
}
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 网络和进程管理

# 端口检查

# 检查端口是否被占用
check_port() {
    local port="$1" protocol="${2:-tcp}"
    [[ "$port" =~ ^[0-9]+$ ]] && [ "$port" -ge 1 ] && [ "$port" -le 65535 ] || return 2
    command -v lsof >/dev/null 2>&1 || { printf '%s\n' '需要 lsof' >&2; return 2; }
    case "$protocol" in
        tcp|TCP) lsof -nP -iTCP:"$port" -sTCP:LISTEN ;;
        udp|UDP) lsof -nP -iUDP:"$port" ;;
        *) printf '%s\n' 'protocol 仅支持 tcp/udp' >&2; return 2 ;;
    esac
}

# 检查端口并显示进程信息
check_port_with_process() {
    # lsof 自身显示 COMMAND/PID,保留多进程结果,不把多个 PID 作为单个 ps 参数。
    check_port "$1" "${2:-tcp}"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

TCP 查监听套接字,UDP 没有 LISTEN 状态。lsof 返回 1 可能表示未匹配,也可能有访问限制,应结合 stderr 和权限判断,不能据此断言系统端口空闲。Linux 可另用 ss,macOS 的 netstat 不能套用 Linux -tuln 参数;protocol 必须参与筛选。

# 进程管理

# 查找并终止进程
kill_process_by_name() {
    local process_name="$1" signal="${2:-TERM}" pids pid status
    if pids=$(pgrep -x "$process_name"); then :; else
        status=$?
        [ "$status" -eq 1 ] && { printf '%s\n' '未找到匹配进程' >&2; return 1; }
        return "$status"
    fi
    while IFS= read -r pid; do
        kill -s "$signal" "$pid" || return 1
        printf '已向 PID %s 发送 %s\n' "$pid" "$signal"
    done <<< "$pids"
}

# 监控进程资源使用
monitor_process() {
    local process_name="$1" interval="${2:-5}" pids pid status
    [[ "$interval" =~ ^[0-9]+$ ]] && [ "$interval" -gt 0 ] || return 2
    while true; do
        if pids=$(pgrep -x "$process_name"); then
            printf '=== %s ===\n' "$(date '+%Y-%m-%d %H:%M:%S')"
            while IFS= read -r pid; do
                ps -p "$pid" -o pid,ppid,%cpu,%mem,comm || return 1
            done <<< "$pids"
        else
            status=$?
            [ "$status" -eq 1 ] || return "$status"
            printf '进程 %s 未运行\n' "$process_name"
        fi
        sleep "$interval" || return 1
    done
}
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
30
31
32

# 实用工具函数

pgrep 的参数仍是正则,-x 要求整个进程名匹配;先用同一 pgrep -x 核对目标,再调用终止函数。不要用于精确身份校验,进程可能退出、PID 可能复用;monitor 用 Ctrl-C 停止。

# 日志记录

# 日志记录函数
log() {
    local level="$1"
    shift
    local message="$*"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo "[$timestamp] [$level] $message" >&2
}

# 使用示例
log "INFO" "开始处理文件"
log "ERROR" "文件不存在"
log "WARN" "磁盘空间不足"
1
2
3
4
5
6
7
8
9
10
11
12
13

# 颜色输出

# 颜色输出函数
color_echo() {
    local color="$1"
    local message="$2"

    case "$color" in
        red)    printf '\033[31m%s\033[0m\n' "$message" ;;
        green)  printf '\033[32m%s\033[0m\n' "$message" ;;
        yellow) printf '\033[33m%s\033[0m\n' "$message" ;;
        blue)   printf '\033[34m%s\033[0m\n' "$message" ;;
        purple) printf '\033[35m%s\033[0m\n' "$message" ;;
        cyan)   printf '\033[36m%s\033[0m\n' "$message" ;;
        *)      printf '%s\n' "$message" ;;
    esac
}

# 使用示例
color_echo "green" "成功完成"
color_echo "red" "发生错误"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 进度条显示

# 简单进度条
show_progress() {
    local current="$1"
    local total="$2"
    local width="${3:-50}"

    [[ "$current" =~ ^[0-9]+$ && "$total" =~ ^[0-9]+$ && "$width" =~ ^[0-9]+$ ]] || return 2
    # 10# 避免 08 等被当作八进制;限制规模避免算术溢出。
    [ "${#current}" -le 6 ] && [ "${#total}" -le 6 ] && [ "${#width}" -le 3 ] || return 2
    current=$((10#$current)); total=$((10#$total)); width=$((10#$width))
    [ "$total" -gt 0 ] && [ "$width" -gt 0 ] && [ "$current" -le "$total" ] || return 2
    local percentage=$((current * 100 / total))
    local filled=$((current * width / total))
    local empty=$((width - filled))

    printf "\r["
    printf "%*s" "$filled" | tr ' ' '='
    printf "%*s" "$empty" | tr ' ' ' '
    printf "] %d%%" "$percentage"
}

# 使用示例
for i in {1..100}; do
    show_progress "$i" 100
    sleep 0.1
done
echo
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

# 数据处理

# CSV 文件处理

# 读取 CSV 文件
read_csv() {
    python3 - "$1" "${2:-,}" <<'PYCODE'
import csv, sys
try:
    with open(sys.argv[1], newline='', encoding='utf-8') as stream:
        for fields in csv.reader(stream, delimiter=sys.argv[2], strict=True):
            print(f'字段数量: {len(fields)}')
            for index, value in enumerate(fields, 1):
                print(f'字段 {index}: {value}')
            print('---')
except (OSError, csv.Error, TypeError, ValueError) as exc:
    print(exc, file=sys.stderr)
    sys.exit(1)
PYCODE
}

# 提取 CSV 特定列
extract_csv_column() {
    python3 - "$1" "$2" "${3:-,}" <<'PYCODE'
import csv, sys
try:
    column = int(sys.argv[2])
    if column < 1:
        raise ValueError('列号从 1 开始')
    with open(sys.argv[1], newline='', encoding='utf-8') as stream:
        writer = csv.writer(sys.stdout, lineterminator='\n')
        for fields in csv.reader(stream, delimiter=sys.argv[3], strict=True):
            if column > len(fields):
                raise ValueError('记录缺少指定列')
            writer.writerow([fields[column - 1]])
except (OSError, csv.Error, TypeError, ValueError) as exc:
    print(exc, file=sys.stderr)
    sys.exit(1)
PYCODE
}
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
30
31
32
33
34
35
36

输入默认 UTF-8、分隔符为单个字符。提取列输出为单列 CSV,含逗号/换行时仍会正确加引号。旧 IFS="," read -r -a fields 与 cut -d, -fN 只适用于不含引号、转义和字段内分隔符的简单文本;"a,b",c 是两个 CSV 字段,不能按逗号直接拆成三个。完整规则见 Python csv 官方文档 (opens new window)。

# 文本搜索和替换

# 批量文本替换
batch_replace() {
    python3 - "$@" <<'PYCODE'
import os, pathlib, shutil, sys, tempfile
try:
    if len(sys.argv) not in (4, 5, 6):
        raise ValueError('用法: batch_replace <原文> <替换> <文件glob> [目录] [--apply]')
    search, replacement, pattern = sys.argv[1:4]
    directory = pathlib.Path(sys.argv[4] if len(sys.argv) >= 5 else '.')
    apply = len(sys.argv) == 6 and sys.argv[5] == '--apply'
    if not search or (len(sys.argv) == 6 and not apply):
        raise ValueError('原文不能为空,执行选项只能是 --apply')
    if not directory.is_dir():
        raise ValueError('目录不存在')
    old, new = search.encode('utf-8'), replacement.encode('utf-8')
    plan = []
    def walk_error(exc):
        raise exc
    import fnmatch
    for parent, _, names in os.walk(directory, onerror=walk_error):
        for name in sorted(names):
            path = pathlib.Path(parent) / name
            if not fnmatch.fnmatchcase(name, pattern) or path.is_symlink() or not path.is_file():
                continue
            data = path.read_bytes()
            if old not in data:
                continue
            backup = path.with_name(path.name + '.bak')
            if os.path.lexists(backup):
                raise FileExistsError(f'备份已存在: {backup}')
            plan.append((path, backup))
    for path, backup in plan:
        print(f'替换: {str(path)!r}; 备份: {str(backup)!r}', flush=True)
        if not apply:
            continue
        # 独占创建备份,不覆盖旧备份;备份成功后才替换源文件。
        with path.open('rb') as source, backup.open('xb') as dest:
            shutil.copyfileobj(source, dest)
        fd, staged = tempfile.mkstemp(prefix='.replace-', dir=path.parent)
        try:
            with os.fdopen(fd, 'wb') as stream:
                stream.write(backup.read_bytes().replace(old, new))
            shutil.copymode(path, staged)
            os.replace(staged, path)
        finally:
            if os.path.exists(staged):
                os.unlink(staged)
except (OSError, ValueError) as exc:
    print(f'替换失败: {exc}', file=sys.stderr)
    sys.exit(1)
PYCODE
}

# 使用示例
batch_replace "old_text" "new_text" "*.txt" "/path/to/files"          # 仅预览
batch_replace "old_text" "new_text" "*.txt" "/path/to/files" --apply
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

搜索与替换参数是 UTF-8 编码的字面量(点号、斜杠、&、反斜杠不作正则或 sed 替换解释);文件模式是只匹配 basename 的 glob,递归子目录且跳过符号链接。旧 sed "s/$search/$replace/g" 会引入正则、替换转义和分隔符冲突,正则处理应另用 sed 指南。

执行前检查所有匹配文件的备份冲突,每个改动保留 .bak。单文件通过同目录临时文件替换,整批不保证原子性;中途失败已完成项仍保留,失败备份可能不完整,必须检查后再恢复。替换会改变 inode,只保留普通权限位,不保留硬链接关系、ACL、扩展属性等元数据;不要对并发修改文件或依赖这些属性的配置直接套用。

# 最佳实践

# 脚本头部模板

#!/usr/bin/env bash
# 脚本描述
# 作者: Your Name
# 日期: $(date +%Y-%m-%d)

set -euo pipefail  # 严格模式
# 按需局部设置 IFS,变量始终正确引用

# 脚本配置
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) || exit 1
readonly SCRIPT_DIR
readonly SCRIPT_NAME="$(basename "$0")"
1
2
3
4
5
6
7
8
9
10
11
12

# 错误处理模板

# 错误处理函数
error_exit() {
    echo "错误: $1" >&2
    exit 1
}

# 检查命令是否存在
check_command() {
    if ! command -v "$1" >/dev/null 2>&1; then
        error_exit "命令 '$1' 未找到,请先安装"
    fi
}

# 检查文件是否存在
check_file() {
    if [ ! -f "$1" ]; then
        error_exit "文件 '$1' 不存在"
    fi
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 使用说明

  1. 复制代码片段:根据需要复制相应的函数到你的脚本中
  2. 修改参数:根据实际情况调整函数参数和默认值
  3. 测试验证:在测试环境中验证代码片段的正确性
  4. 错误处理:添加适当的错误处理和日志记录

# 注意事项

  • 所有函数都使用 local 声明局部变量
  • 理解 set -euo pipefail 的上下文边界,关键写入显式检查状态
  • 错误信息输出到 stderr (>&2)
  • 函数参数使用默认值语法 ${param:-default}
  • 使用 command -v 检查命令是否存在

通过这个代码片段集合,你可以快速构建高效的 Shell 脚本,提高日常开发效率! 🚀

#Shell#snippet#Linux#cs-fundamentals
上次更新: 2026/10/26, 22:32:55
Shell 常用命令速查手册
逆向

← Shell 常用命令速查手册 逆向→

最近更新
01
Wrangler 使用指引
11-06
02
ADB 图形化与手机端调试工具选型
10-29
03
Shell 执行模型与环境加载
10-26
更多文章>
Theme by Vdoing | Copyright © 2019-2026 Jacky | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式