Linux基础(信号、变量)

Shell 脚本高级特性完全指南

信号与信号捕捉工具 trap

信号概述

信号是操作系统与运行程序通信的机制,用于响应特定事件:

  • 用户按下 Ctrl+C 时发送 SIGINT 信号
  • kill 命令默认发送 SIGTERM 信号
  • 系统异常时自动发送特定信号

信号列表 (64个信号)

传统信号 (1-31号)

编号 信号名 描述
1 SIGHUP 终端挂起或控制进程终止
2 SIGINT 中断进程(通常由 Ctrl+C 产生)
3 SIGQUIT 退出进程并生成核心转储文件(通常由 Ctrl+\ 产生)
4 SIGILL 非法指令
5 SIGTRAP 跟踪/断点陷阱
6 SIGABRT 由 abort(3) 产生的信号
7 SIGBUS 总线错误(非法的内存地址)
8 SIGFPE 算术异常(如除零错误)
9 SIGKILL 立即杀死进程(不能被捕获、阻塞或忽略)
10 SIGUSR1 用户定义的信号 1
11 SIGSEGV 段错误(非法的内存访问)
12 SIGUSR2 用户定义的信号 2
13 SIGPIPE 管道破裂(向没有读端的管道写数据)
14 SIGALRM 闹钟信号(由 alarm(2) 产生的信号)
15 SIGTERM 终止进程(请求进程终止)
16 SIGSTKFLT 协处理器栈错误
17 SIGCHLD 子进程状态改变(子进程停止或退出)
18 SIGCONT 继续执行被停止的进程
19 SIGSTOP 停止进程的执行(不能被捕获、阻塞或忽略)
20 SIGTSTP 停止进程的执行(通常由 Ctrl+Z 产生)
21 SIGTTIN 后台进程试图从控制终端读取
22 SIGTTOU 后台进程试图向控制终端写入
23 SIGURG 套接字上有紧急数据可读
24 SIGXCPU CPU 时间限制超时
25 SIGXFSZ 文件大小限制超时
26 SIGVTALRM 虚拟定时器信号
27 SIGPROF 剖析定时器信号
28 SIGWINCH 窗口大小改变
29 SIGIO I/O 可能事件
30 SIGPWR 电源故障(重启)
31 SIGSYS 非法的系统调用(SVID 扩展)

实时信号 (34-64号)

编号 信号名 描述
34 SIGRTMIN 实时信号最小值(用户自定义)
35 SIGRTMIN+1 用户自定义实时信号
36 SIGRTMIN+2 用户自定义实时信号
37 SIGRTMIN+3 用户自定义实时信号
38 SIGRTMIN+4 用户自定义实时信号
39 SIGRTMIN+5 用户自定义实时信号
40 SIGRTMIN+6 用户自定义实时信号
41 SIGRTMIN+7 用户自定义实时信号
42 SIGRTMIN+8 用户自定义实时信号
43 SIGRTMIN+9 用户自定义实时信号
44 SIGRTMIN+10 用户自定义实时信号
45 SIGRTMIN+11 用户自定义实时信号
46 SIGRTMIN+12 用户自定义实时信号
47 SIGRTMIN+13 用户自定义实时信号
48 SIGRTMIN+14 用户自定义实时信号
49 SIGRTMIN+15 用户自定义实时信号
50 SIGRTMAX-14 用户自定义实时信号
51 SIGRTMAX-13 用户自定义实时信号
52 SIGRTMAX-12 用户自定义实时信号
53 SIGRTMAX-11 用户自定义实时信号
54 SIGRTMAX-10 用户自定义实时信号
55 SIGRTMAX-9 用户自定义实时信号
56 SIGRTMAX-8 用户自定义实时信号
57 SIGRTMAX-7 用户自定义实时信号
58 SIGRTMAX-6 用户自定义实时信号
59 SIGRTMAX-5 用户自定义实时信号
60 SIGRTMAX-4 用户自定义实时信号
61 SIGRTMAX-3 用户自定义实时信号
62 SIGRTMAX-2 用户自定义实时信号
63 SIGRTMAX-1 用户自定义实时信号
64 SIGRTMAX 实时信号最大值(用户自定义)

重要提示

  1. SIGKILL (9)SIGSTOP (19) 不能被捕获、阻塞或忽略
  2. 实时信号(34-64)没有预定义含义,用于应用程序自定义
  3. 信号 32 和 33 为系统保留,未列出
  4. 使用 kill -L 命令可查看当前系统的完整信号列表

trap 基本功能

trap 是 Shell 脚本中用于捕获和处理信号的强大工具:

  • 捕获特定信号并执行指定操作
  • 实现优雅退出和资源清理
  • 忽略特定信号防止意外中断
  • 记录错误日志和诊断信息

基本语法

trap command signal [signal ...]
参数 说明
command 信号发生时执行的命令或函数
signal 信号名(大小写不敏感,SIG前缀可选)或信号数值
'' 忽略信号(空字符串)
- 恢复信号的默认行为

常用信号处理场景

信号 典型场景 默认行为
SIGINT 用户按下 Ctrl+C 中断脚本 终止进程
SIGTERM 系统请求进程终止 终止进程
SIGHUP 终端断开连接 终止进程
SIGQUIT 用户按下 Ctrl+\ 退出 终止进程并生成核心转储
SIGTSTP 用户按下 Ctrl+Z 暂停 暂停进程
SIGCONT 继续被暂停的进程 继续进程

trap 使用示例

示例 1:捕获 SIGINT 执行清理

#!/bin/bash

cleanup() {
    echo "脚本被中断,正在执行清理操作..."
    # 清理资源:关闭文件、删除临时文件等
    rm -f /tmp/tempfile
    exit 1
}

# 捕获 SIGINT 信号并执行 cleanup 函数
trap cleanup SIGINT

echo "脚本正在运行,按 Ctrl+C 测试信号捕获..."
while true; do
    sleep 1
done

示例 2:捕获多个信号

#!/bin/bash

handle_signals() {
    case $1 in
        SIGINT)
            echo "接收到中断信号,正在退出..."
            ;;
        SIGTERM)
            echo "接收到终止信号,正在退出..."
            ;;
        *)
            echo "接收到未知信号: $1"
            ;;
    esac
    # 执行清理操作
    exit 1
}

# 捕获多个信号
trap 'handle_signals SIGINT' SIGINT
trap 'handle_signals SIGTERM' SIGTERM

echo "脚本正在运行,等待信号(可发送 SIGINT 或 SIGTERM 测试)..."
while true; do
    sleep 1
done

示例 3:忽略特定信号

#!/bin/bash

# 忽略 CTRL+C 信号 (SIGINT)
trap '' INT

echo "已忽略 Ctrl+C 中断信号,脚本将无法通过 Ctrl+C 终止"
echo "测试:尝试按下 Ctrl+C..."
sleep 5
echo "测试完成"

示例 4:恢复默认行为

#!/bin/bash

# 初始忽略 SIGINT
trap '' SIGINT
echo "当前忽略 Ctrl+C"

# 5秒后恢复默认行为
sleep 5
trap - SIGINT
echo "已恢复 Ctrl+C 的默认行为"

echo "现在可以按 Ctrl+C 终止脚本..."
while true; do
    sleep 1
done

mktemp(临时文件创建工具)

基本语法

mktemp [OPTION]... [TEMPLATE]
  • TEMPLATE:必须包含至少 6 个连续 X (如 tmp.XXXXXX)

常用选项

选项 说明
-d 创建临时目录
-u 仅打印名称(不安全)
-q 失败时不输出诊断信息
--suffix=SUFF 添加后缀
-p DIR 指定父目录

使用示例

# 创建临时文件
mktemp tmp.XXXXXX

# 创建临时目录
mktemp -d tmpdir.XXXXXX

# 指定父目录
mktemp -p /custom/path tmp.XXXXXX

# 添加后缀
mktemp --suffix=.log tmpXXXXXX

# 预览模式
mktemp -u tmp.XXXXXX

注意事项

  1. 默认权限:仅所有者可访问 (600)
  2. 需手动删除临时文件
  3. 避免使用 -u 防止竞态条件

install 命令

基本语法

install [OPTION]... SOURCE DEST
install [OPTION]... SOURCE... DIRECTORY
install [OPTION]... -d DIRECTORY...

常用选项

选项 说明
-d 创建目录
-m MODE 设置权限
-o OWNER 设置所有者 (需 root)
-g GROUP 设置所属组
-p 保留时间戳
-s 删除符号表
-t DIR 指定目标目录

使用示例

# 复制文件并设置权限
install -m 0755 script.sh /usr/local/bin/

# 复制文件并设置所有者
install -o user -g group file.txt /target/

# 创建目录
install -d /path/to/newdir

# 复制多个文件
install file1 file2 /target/directory/

# 保留时间戳
install -p source dest

注意事项

  1. 需要足够权限修改目标位置
  2. 默认覆盖已存在文件(使用 --backup 备份)
  3. 组合选项实现复杂操作

数组操作

普通数组

# 声明与赋值
arr[0]="A"
arr[1]="B"
arr=("A" "B" "C")

# 访问元素
echo ${arr[1]}  # 输出 "B"

# 遍历元素
for item in "${arr[@]}"; do
    echo $item
done

# 数组长度
echo ${#arr[@]}  # 输出 3

# 删除元素
unset arr[1]  # 删除索引1的元素

# 删除整个数组
unset arr

关联数组

# 声明与赋值
declare -A assoc_arr
assoc_arr["key1"]="value1"
assoc_arr["key2"]="value2"

# 访问元素
echo ${assoc_arr["key1"]}  # 输出 "value1"

# 遍历键值对
for key in "${!assoc_arr[@]}"; do
    echo "$key: ${assoc_arr[$key]}"
done

# 检查键存在
if [[ -v assoc_arr["key1"] ]]; then
    echo "键存在"
fi

# 删除操作
unset assoc_arr["key1"]  # 删除单个元素
unset assoc_arr         # 删除整个数组

字符串切片

常用方法

# ${string:start:length} 语法
str="Hello, World!"
echo ${str:7:5}  # 输出 "World"

# ${string:start} 语法
str="Hello, World!"
echo ${str:7}    # 输出 "World!"

# ${string: -length} 语法
str="Hello, World!"
echo ${str: -6}  # 输出 "World!"

# 使用 cut 命令
echo "Hello, World!" | cut -c 8-12  # 输出 "World"

# 模式匹配
str="Hello123World"
num=${str##*[!0-9]*}
num=${num%%*[!0-9]*}
echo $num  # 输出 "123"

变量的高级用法

变量配置方式表

配置方式 未配置 空字符串 已配置非空
var=${str-expr} var=expr var=“” var=$str
var=${str:-expr} var=expr var=expr var=$str
var=${str+expr} var=“” var=“” var=expr
var=${str:+expr} var=“” var=“” var=expr
var=${str=expr} str=expr, var=expr str=“”, var=“” var=$str
var=${str:=expr} str=expr, var=expr str=expr, var=expr var=$str
var=${str?expr} 报错退出 通常不触发 var=$str
var=${str:?expr} 报错退出 报错退出 var=$str

注意

  1. "保持未赋值状态"可能意味着赋值为空字符串
  2. var=${str=expr}在str为空时的行为不常见,应避免使用
  3. 具体行为可能因Shell版本而异

变量的间接引用

引用方法

# ${!var} 语法 (Bash 4.3+)
var_name="my_var"
my_var="Hello"
echo ${!var_name}  # 输出 "Hello"

# eval 命令
var_name="my_var"
my_var="Hello"
eval temp_var=\$$var_name
echo $temp_var  # 输出 "Hello"

注意事项

  1. ${!var}:更安全简洁(推荐)
  2. eval:兼容性好但需防注入攻击
  3. 避免处理用户输入时使用间接引用

IFS(Internal Field Separator)

基本概念

# 默认值:空格、制表符、换行符
echo "默认IFS: '$IFS'"

# 修改IFS
OLDIFS=$IFS
IFS=','

# 恢复IFS
IFS=$OLDIFS

使用示例

#!/bin/bash
# 处理CSV数据
data="John,30,New York"

# 保存原始IFS
OLDIFS=$IFS
IFS=','

# 读取字段
read -r name age city <<< "$data"
echo "Name: $name"
echo "Age: $age"
echo "City: $city"

# 恢复IFS
IFS=$OLDIFS

注意事项

  1. 修改前保存原始值
  2. 子shell修改不影响父shell
  3. 特殊字符需正确处理
  4. 影响命令:read, for循环, 参数扩展等

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇