shell脚本

Shell内容讲解

一、Shell 脚本基础概念

  1. 什么是 Shell 脚本?

    Shell 脚本是一个包含一系列 Shell 命令的文本文件,用于自动化执行任务(如文件操作、程序调用、系统管理等)。

  2. Shell 类型

    • bash(Bourne-Again Shell):Linux 系统默认 Shell。
    • sh(Bourne Shell):更早期的标准 Shell。
    • zshksh 等:其他变体,语法略有差异。
      推荐使用 bash ,本教程以 bash 为例。

二、编写第一个 Shell 脚本

1. 创建脚本文件
bash 复制代码
# 创建文件并编辑
vim hello.sh
2. 编写脚本内容
bash 复制代码
#!/bin/bash          # Shebang 行:指定脚本解释器为 bash
echo "Hello World!"  # 输出文本
3. 赋予执行权限
bash 复制代码
chmod +x hello.sh    # 添加可执行权限
4. 运行脚本
bash 复制代码
./hello.sh           # 直接运行(需在脚本所在目录)
# 或
bash hello.sh        # 显式指定解释器

输出

Hello World!

三、Shell 脚本核心语法

以下是 Shell 脚本语法和使用的超详细指南,结合实用示例,涵盖从基础到进阶的核心内容:


一、Shell 脚本基础结构

1. Shebang 行

Shebang 行(又称 hashbang)是脚本文件的第一行,用于指定执行该脚本的解释器。当你在终端中直接运行脚本时,系统会根据 Shebang 行选择正确的解释器

  • 作用:指定脚本使用的解释器。

  • 语法

    bash 复制代码
    #!/bin/bash  # 使用 bash 解释器
    #!/bin/sh   # 使用 sh 解释器
2. 注释
  • 单行注释:以 # 开头。

    bash 复制代码
    # 这是一个注释
  • 多行注释(通过字符串技巧):

    bash 复制代码
    : '
    这是
    多行注释
    '

二、变量与数据类型

1. 变量定义与使用
  • 定义变量 (无数据类型,默认为字符串):

    bash 复制代码
    name="Alice"      # 字符串
    count=10          # 整数
    files=$(ls)       # 命令执行结果赋值
    today=$(date +%F) # 日期格式化为字符串
  • 使用变量

    bash 复制代码
    echo $name        # 直接引用
    echo "${name}"    # 推荐用 {} 包裹变量名
2. 变量作用域
  • 局部变量:默认仅在当前脚本或函数内有效。

  • 环境变量 :通过 export 导出,子进程可继承。

    bash 复制代码
    export PATH="/usr/local/bin:$PATH"
3. 特殊变量
变量 含义
$HOME 当前用户主目录的路径
$PATH 可执行文件路径的列表
$0 脚本名称
$1-$9 第 1 到第 9 个参数
$# 参数个数
$@ 所有参数(列表形式)
$* 所有参数(字符串形式)
$? 上一条命令的退出状态码,0通常表示没有错误,非0值表示有错误
$$ 当前脚本的进程 ID
$! 最后一个后台命令的进程 ID
bash 复制代码
echo $PATH 

执行结果

三、条件判断

1. 基本语法
bash 复制代码
if [ 条件 ]; then
  # 命令
elif [ 条件 ]; then
  # 命令
else
  # 命令
fi
2. 条件测试类型
  • 数值比较

lt(less than):小于

le(less than or equal to):小于等于

gt(greater than):大于

ge(greater than or equal to):大于等于

eq(equal to):等于

ne(not equal to):不等于

bash 复制代码
[ $a -eq $b ]  # a == b
[ $a -ne $b ]  # a != b
[ $a -gt $b ]  # a > b
[ $a -lt $b ]  # a < b
  • 字符串比较

    bash 复制代码
    [ "$str1" == "$str2" ]  # 字符串相等
    [ "$str1" != "$str2" ]  # 字符串不等
    [ -z "$str" ]           # 字符串为空
    [ -n "$str" ]           # 字符串非空
  • 文件/目录测试

    bash 复制代码
    [ -f "file.txt" ]  # 文件存在且为普通文件
    [ -d "dir" ]       # 目录存在
    [ -e "path" ]      # 文件/目录存在
    [ -r "file" ]      # 文件可读
    [ -w "file" ]      # 文件可写
    [ -x "file" ]      # 文件可执行
3. 逻辑运算符
bash 复制代码
[ 条件1 ] && [ 条件2 ]  # AND
[ 条件1 ] || [ 条件2 ]  # OR
! [ 条件 ]              # NOT
4. 示例:检查文件是否存在
bash 复制代码
#!/bin/bash
file="data.txt"
if [ -f "$file" ]; then
  echo "$file 存在"
else
  echo "$file 不存在"
fi

四、循环结构

1. for 循环
  • 遍历列表

    bash 复制代码
    for i in 1 2 3; do
      echo "数字: $i"
    done
  • 遍历命令输出

    bash 复制代码
    for file in $(ls *.txt); do
      echo "处理文件: $file"
    done
2. while 循环
bash 复制代码
count=1
while [ $count -le 5 ]; do
  echo "计数: $count"
  ((count++))
done
3. until 循环
bash 复制代码
count=1
until [ $count -gt 5 ]; do
  echo "计数: $count"
  ((count++))
done
4. 循环控制
  • break:退出循环。
  • continue:跳过当前迭代。

五、函数

1. 定义与调用
bash 复制代码
# 定义函数
greet() {
  echo "Hello, $1!"
}

# 调用函数
greet "Alice"  # 输出:Hello, Alice!
2. 返回值
  • 通过 return 返回状态码(0-255)

    bash 复制代码
    is_even() {
      if [ $(($1 % 2)) -eq 0 ]; then
        return 0  # 偶数,成功
      else
        return 1  # 奇数,失败
      fi
    }
    
    is_even 4
    echo $?  # 输出 0
  • 通过 echo 返回数据

    bash 复制代码
    add() {
      echo $(($1 + $2))
    }
    
    result=$(add 3 5)
    echo $result  # 输出 8
    • 外层 $(( )):表示这是一个算术运算表达式,Shell 会计算括号内的内容并返回结果。

    • 内部的 1 :表示函数的第一个参数(位置参数), 1:表示函数的第一个参数(位置参数), 1:表示函数的第一个参数(位置参数), 符号用于引用参数的值。

六、参数处理

1. 位置参数
bash 复制代码
#!/bin/bash
echo "脚本名: $0"
echo "第一个参数: $1"
echo "所有参数: $@"
2. 参数解析(getopts
bash 复制代码
#!/bin/bash
while getopts ":u:p:" opt; do  # 静默模式(以 : 开头)
  case $opt in
    u) user="$OPTARG" ;;
    p) pass="$OPTARG" ;;
    :) echo "错误:选项 -$OPTARG 需要参数" >&2; exit 1 ;;  # 缺少参数
    \?) echo "错误:无效选项 -$OPTARG" >&2; exit 1 ;;      # 未知选项
  esac
done
shift $((OPTIND - 1))  # 移除已解析的选项,保留剩余参数

运行示例:

bash 复制代码
./script.sh -u alice -p 1234
代码功能
  1. 通过 getopts 解析命令行参数 -u-p,分别获取用户名和密码。
  2. 将参数值保存到变量 userpass 中。
  3. 输出用户和密码信息。

getopts 用法详解

getopts 是 Bash 中解析命令行选项的标准工具,适合处理短选项(如 -u-p)。

1. 基本语法
bash 复制代码
while getopts "选项字符串" opt; do
  case $opt in
    # 处理逻辑
  esac
done
  • 选项字符串 :定义支持的选项和是否带参数。
    • 单个字母表示选项(如 u 对应 -u)。
    • 字母后加 : 表示该选项需要参数(如 u: 表示 -u value)。
    • 若选项字符串以 : 开头(如 ":u:p:"),则静默处理错误(需自行捕获)。
2. 内置变量
  • $OPTARG:当前选项的参数值(仅当选项需要参数时有效)。
  • $OPTIND :下一个待处理参数的索引,通常用于 shift 跳过已解析的参数。
3. 错误处理
  • 无效选项opt 会被赋值为 ?
  • 缺少参数 :若选项字符串以 : 开头,opt 会被赋值为 :,否则为 ?

对上面示例代码的改进

  1. 对必选参数进行校验 :在示例中,如果用户未提供 -u-p,变量 userpass 可能为空,但脚本不会报错。
  2. 清理已解析参数 :使用 shift $((OPTIND - 1)),避免后续处理位置参数时包含已解析的选项。

改进后的代码

bash 复制代码
#!/bin/bash
# 添加错误处理和参数校验
while getopts ":u:p:" opt; do
  case $opt in
    u) user="$OPTARG" ;;
    p) pass="$OPTARG" ;;
    :) echo "错误:选项 -$OPTARG 需要参数" >&2; exit 1 ;;
    \?) echo "错误:无效选项 -$OPTARG" >&2; exit 1 ;;
  esac
done

# 校验必须参数
if [[ -z "$user" || -z "$pass" ]]; then
  echo "错误:必须提供 -u 和 -p 参数" >&2
  echo "用法: $0 -u <用户> -p <密码>" >&2
  exit 1
fi

shift $((OPTIND - 1))  # 清理已解析的选项
echo "用户: $user, 密码: $pass"
  • 使用 [[ ]] 更安全(避免变量未定义的错误)
    • [[ -z "$var" ]] # 推荐
    • [ -z "$var" ] # 也可用,但需注意变量未定义的情况

正确执行
bash 复制代码
$ ./script.sh -u alice -p 1234
用户: alice, 密码: 1234
错误情况
  1. 无效选项

    bash 复制代码
    $ ./script.sh -a
    错误:无效选项 -a
  2. 缺少参数

    bash 复制代码
    $ ./script.sh -u
    错误:选项 -u 需要参数
  3. 未提供必选参数

    bash 复制代码
    $ ./script.sh -u alice
    错误:必须提供 -u 和 -p 参数
    用法: ./script.sh -u <用户> -p <密码>

  • getopts 是解析命令行选项的标准工具,需结合 case 和内置变量使用。
  • 通过选项字符串定义选项是否需要参数(如 u:)。
  • 错误处理需区分"无效选项"和"缺少参数",并校验必要参数。
  • 使用 shift $((OPTIND - 1)) 清理已解析的参数。

七、错误处理

1. 错误退出
bash 复制代码
if [ ! -f "file.txt" ]; then
  echo "错误:文件不存在" >&2  # 输出到标准错误
  exit 1
fi
2. 捕获信号
bash 复制代码
trap "echo '脚本被中断!'; exit" SIGINT
3. 调试模式
bash 复制代码
set -x   # 打印执行的命令
set -e   # 遇到错误立即退出
set -o pipefail  # 管道命令失败时退出

八、高级技巧

1. 数组操作
bash 复制代码
# 定义数组
fruits=("apple" "banana" "cherry")

# 访问元素
echo ${fruits[0]}  # apple

# 遍历数组
for fruit in "${fruits[@]}"; do
  echo "$fruit"
done

# 数组长度
echo ${#fruits[@]}  # 3

在 Bash 脚本中,${fruits[@]} 中的 @ 符号用于 展开数组的所有元素,并确保每个元素被视为独立的字符串(即使元素包含空格或特殊字符)。以下是详细解释:


1.${num[@]}

安全展开数组所有元素,保留每个元素的独立性,是遍历数组的推荐方式。

2.@ 符号

代表数组的全部元素,配合双引号使用时,确保数据完整性和可靠性。
1. 数组定义与 @ 的作用

假设数组 fruits 定义如下:

bash 复制代码
fruits=("apple" "banana" "orange with spaces" "grape")
  • ${fruits[@]}

    展开数组的所有元素,每个元素保持独立。
    结果"apple" "banana" "orange with spaces" "grape"

  • 对比 ${fruits[*]}

    展开数组的所有元素,合并成一个字符串(默认用空格分隔)。
    结果"apple banana orange with spaces grape"


2. 关键区别
语法 行为 适用场景
"${fruits[@]}" 每个元素保持独立,即使包含空格也会正确分割 遍历数组元素,保留原始数据
"${fruits[*]}" 所有元素合并成一个字符串,用 IFS 的第一个字符(默认空格)分隔 需要整体输出数组内容时
${fruits[@]}(无引号) 元素可能被二次分词(若元素含空格或通配符,会被拆分成多个部分) 不推荐,可能导致意外行为
${fruits[*]}(无引号) 同上,合并后的字符串可能被二次分词 不推荐

3. 示例演示

场景 1:遍历数组元素(正确方式)
bash 复制代码
for fruit in "${fruits[@]}"; do
  echo "Fruit: $fruit"
done

输出

Fruit: apple
Fruit: banana
Fruit: orange with spaces
Fruit: grape
  • 即使元素包含空格(如 "orange with spaces"),也会被当作一个整体处理。
场景 2:错误用法(无引号)
bash 复制代码
for fruit in ${fruits[@]}; do
  echo "Fruit: $fruit"
done

输出

Fruit: apple
Fruit: banana
Fruit: orange
Fruit: with
Fruit: spaces
Fruit: grape
  • "orange with spaces" 被拆分成 3 个"虚假"元素,导致逻辑错误!

4. 技术细节
  • 引号的重要性

    使用 "${fruits[@]}" 时,双引号包裹是必须的,确保元素中的空格和特殊字符被保留。

  • 下标访问

    • fruits[0] 表示第一个元素(Bash 数组默认从 0 开始)。
    • fruits[-1] 表示最后一个元素。
  • 数组长度
    ${#fruits[@]} 返回数组元素个数。


5. 其他相关用法
  • 遍历索引

    bash 复制代码
    for i in "${!fruits[@]}"; do
      echo "索引 $i: ${fruits[i]}"
    done
  • 数组拼接

    bash 复制代码
    new_fruits=("${fruits[@]}" "kiwi" "mango")
  • 函数参数传递

    bash 复制代码
    print_args() {
      for arg in "$@"; do  # "$@" 和 "${array[@]}" 行为一致
        echo "$arg"
      done
    }
    print_args "${fruits[@]}"
2. 关联数组
bash 复制代码
declare -A user
user["name"]="Alice"
user["age"]=30
echo "${user["name"]}"  # Alice
3. 子 Shell 和命令替换
bash 复制代码
# 子 Shell 中执行命令
(cd /tmp && ls)  # 不影响当前目录

# 命令替换
files=$(ls)

九、实战示例

1. 备份日志文件
bash 复制代码
#!/bin/bash
backup_dir="/backup/logs"
log_dir="/var/log"
timestamp=$(date +%Y%m%d)

mkdir -p "$backup_dir"
tar -czf "$backup_dir/logs_$timestamp.tar.gz" "$log_dir"
echo "备份完成: $backup_dir/logs_$timestamp.tar.gz"
2. 监控 CPU 使用率
bash 复制代码
#!/bin/bash
threshold=80
cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}')

if (( $(echo "$cpu_usage > $threshold" | bc -l) )); then
  echo "警告:CPU 使用率 ${cpu_usage}% 超过阈值 ${threshold}%!" | mail -s "CPU 警报" admin@example.com
fi
3. 批量重命名文件
bash 复制代码
#!/bin/bash
prefix="photo"
counter=1

for file in *.jpg; do
  new_name="${prefix}_$(printf "%03d" $counter).jpg"
  mv "$file" "$new_name"
  ((counter++))
done
4.自启动脚本

思路分析:

首先,配置文件列出需要启动的程序及其路径和参数。这样只需编辑配置文件,而不必修改脚本本身,提高灵活性和可维护性。

然后,脚本需要读取配置文件中的每个条目,并依次启动这些程序。需要考虑每个程序是否已经在运行,避免重复启动。这可以通过检查进程ID(PID)文件或者使用pgrep命令来实现。

另外,需要处理程序的启动顺序和依赖关系。如果某些程序需要先于其他程序启动,或者需要等待某个条件满足,脚本需要能够处理这些情况。

还需要考虑日志记录,记录每个程序的启动状态,方便后续排查问题。可以输出到系统日志或者自定义的日志文件中。

安全性也是一个方面。需要确保脚本和配置文件有适当的权限,防止未经授权的修改。特别是当脚本以root权限运行时,需要小心处理。

实现步骤:

  1. 创建一个配置文件,例如programs.conf,每行定义一个程序,包含名称、路径、参数等。

  2. 脚本读取该配置文件,逐行处理。

  3. 对于每个程序,检查是否已经在运行,如果未运行,则启动它。

  4. 记录启动结果到日志文件。

  5. 提供命令行参数,例如start、stop、restart等,以控制程序的行为。

bash 复制代码
#!/bin/bash

# 配置文件路径
CONFIG_FILE="$(dirname "$0")/programs.conf"
# 日志文件路径
LOG_FILE="/var/log/auto_start.log"
# PID目录存放进程ID文件
PID_DIR="/var/run/auto_start"

# 创建PID目录
mkdir -p "$PID_DIR"

# 日志记录函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

# 读取配置文件并启动程序
start_programs() {
    while read -r line; do
        # 忽略注释和空行
        [[ "$line" =~ ^#.*$ || -z "$line" ]] && continue
        
        # 解析配置行: 名称, 命令, 参数
        name=$(echo "$line" | cut -d'|' -f1 | xargs)
        command=$(echo "$line" | cut -d'|' -f2 | xargs)
        args=$(echo "$line" | cut -d'|' -f3 | xargs)
        
        pid_file="${PID_DIR}/${name}.pid"
        
        # 检查进程是否已在运行
        if [ -f "$pid_file" ]; then
            pid=$(cat "$pid_file")
            if ps -p "$pid" > /dev/null 2>&1; then
                log "程序 $name 已在运行 (PID: $pid)"
                continue
            fi
        fi
        
        # 启动程序并记录PID
        eval "$command $args" >> "${PID_DIR}/${name}.log" 2>&1 &
        pid=$!
        echo $pid > "$pid_file"
        log "启动 $name 成功 (PID: $pid)"
    done < "$CONFIG_FILE"
}

# 停止所有程序
stop_programs() {
    for pid_file in "$PID_DIR"/*.pid; do
        [ -f "$pid_file" ] || continue
        
        name=$(basename "$pid_file" .pid)
        pid=$(cat "$pid_file")
        
        if kill -0 "$pid" > /dev/null 2>&1; then
            kill "$pid"
            log "已停止 $name (PID: $pid)"
        else
            log "程序 $name 未运行"
        fi
        rm -f "$pid_file"
    done
}

# 查看程序状态
status_programs() {
    for pid_file in "$PID_DIR"/*.pid; do
        [ -f "$pid_file" ] || continue
        
        name=$(basename "$pid_file" .pid)
        pid=$(cat "$pid_file")
        
        if ps -p "$pid" > /dev/null 2>&1; then
            echo "$name 正在运行 (PID: $pid)"
        else
            echo "$name 未运行"
        fi
    done
}

# 主程序逻辑
case "$1" in
    start)
        start_programs
        ;;
    stop)
        stop_programs
        ;;
    restart)
        stop_programs
        sleep 2
        start_programs
        ;;
    status)
        status_programs
        ;;
    *)
        echo "用法: $0 {start|stop|restart|status}"
        exit 1
esac

📁 配套配置文件示例 (programs.conf)

conf 复制代码
# 格式: 名称 | 执行命令 | 参数
web_server | /usr/bin/python3 | -m http.server 8080
logger | /usr/bin/logger | --tag auto_start
monitor | /usr/bin/nmon | -f -s 5

📜 脚本功能说明

  1. 配置文件管理

    • 使用programs.conf文件定义需要自启动的程序
    • 支持注释(以#开头的行)
    • 格式:程序名称 | 执行命令 | 参数
  2. 进程管理

    • 自动生成PID文件(存放于/var/run/auto_start
    • 启动前检查进程是否已存在
    • 支持停止所有程序
  3. 日志记录

    • 操作日志记录到/var/log/auto_start.log
    • 每个程序单独记录输出到/var/run/auto_start/<程序名>.log
  4. 操作命令

    bash 复制代码
    # 启动所有程序
    sudo ./auto_start.sh start
    
    # 停止所有程序
    sudo ./auto_start.sh stop
    
    # 重启所有程序
    sudo ./auto_start.sh restart
    
    # 查看运行状态
    sudo ./auto_start.sh status

🔧 部署说明

  1. 将脚本保存为/usr/local/bin/auto_start.sh

  2. 创建配置文件/etc/auto_start.conf

  3. 设置可执行权限:

    bash 复制代码
    chmod +x /usr/local/bin/auto_start.sh
  4. 配置systemd服务(实现开机自启):

    bash 复制代码
    # /etc/systemd/system/auto-start.service
    [Unit]
    Description=Auto Start Programs
    After=network.target
    
    [Service]
    Type=oneshot
    ExecStart=/usr/local/bin/auto_start.sh start
    RemainAfterExit=yes
    
    [Install]
    WantedBy=multi-user.target
  5. 启用服务:

    bash 复制代码
    systemctl enable auto-start.service

⚠️ 注意事项

  1. 需要使用root权限运行(建议通过systemd管理)
  2. 程序参数包含特殊字符时需正确转义
  3. PID文件可能需要在系统重启后清理
  4. 建议对敏感命令进行权限控制

十、Shell 脚本最佳实践

  1. 代码规范

    • 使用 shellcheck 检查语法。
    • 变量名使用小写,常量用大写。
    • 添加清晰的注释。
  2. 安全性

    • 避免 eval 和未过滤的用户输入。
    • 使用 set -euo pipefail 增强错误处理。
  3. 性能优化

    • 减少子 Shell 使用。
    • 避免在循环中调用外部命令。

/etc/shells文件解析

/etc/shells 是 Linux 和类 Unix 系统中一个重要的配置文件,它列出了系统认可的合法 Shell 路径。以下是关于该文件的详细讲解:

1. 文件作用

  • 定义合法 Shell
    /etc/shells 记录了系统允许用户使用的 Shell 程序路径。用户登录或切换 Shell 时,系统会检查其 Shell 是否在此列表中。
  • 安全限制
    某些服务(如 FTP、SSH)会验证用户的 Shell 是否在 /etc/shells 中。如果不在,可能拒绝登录(例如 FTP 用户若使用未列出的 Shell,会报错 This account is not available)。

2. 文件格式

  • 每行一个路径
    文件中的每一行都是一个 Shell 的绝对路径,例如:

    plaintext 复制代码
    /bin/sh
    /bin/bash
    /usr/bin/zsh
    /usr/bin/fish

3. 查看文件内容

使用以下命令查看当前系统认可的 Shell:

bash 复制代码
cat /etc/shells

输出示例:

/bin/sh
/bin/bash
/usr/bin/bash
/bin/dash
/usr/bin/zsh

4. 与用户账户的关系

  • 用户默认 Shell

    用户的默认 Shell 定义在 /etc/passwd 文件的最后一个字段。例如:

    plaintext 复制代码
    alice:x:1001:1001:Alice:/home/alice:/bin/bash

    这里用户 alice 的 Shell 是 /bin/bash

  • 切换 Shell

    使用 chsh 命令切换用户 Shell 时,系统会检查目标 Shell 是否在 /etc/shells 中:

    bash 复制代码
    chsh -s /usr/bin/zsh  # 需确保 /usr/bin/zsh 已添加到 /etc/shells

修改完后要注销后才能生效

5. 如何添加新的 Shell

如果安装了新的 Shell(如 fishzsh),需手动将其路径添加到 /etc/shells

  1. 编辑文件(需 root 权限):

    bash 复制代码
    sudo nano /etc/shells
  2. 添加路径

    plaintext 复制代码
    # 添加新安装的 Shell 路径
    /usr/bin/fish
  3. 验证

    bash 复制代码
    cat /etc/shells | grep fish

6. 常见问题与解决

  • 问题 1:用户无法登录
    原因 :用户的 Shell 不在 /etc/shells 中。
    解决

    1. 通过恢复模式或单用户模式进入系统。
    2. 将缺失的 Shell 路径添加到 /etc/shells
  • 问题 2:chsh 报错 invalid shell
    原因 :目标 Shell 未在 /etc/shells 中注册。
    解决

    按上述步骤添加 Shell 路径。


7. 实际应用场景

  • 限制 FTP 用户
    若 FTP 服务(如 vsftpd)配置为仅允许使用 /usr/sbin/nologin,需确保该路径存在于 /etc/shells
  • 容器环境
    在 Docker 容器中,若用户 Shell 被设置为 /bin/false,需确认该路径已添加到 /etc/shells

总结

  • /etc/shells 是系统合法 Shell 的白名单,直接影响用户登录和 Shell 切换。
  • 维护此文件时需谨慎,避免误删默认 Shell 路径导致登录问题。
  • 添加新 Shell 后,用户需通过 chsh 切换才能生效。

此生谁料,心在天山,身老沧洲。 ---陆游

相关推荐
流星白龙1 小时前
【Linux】使用管道实现一个简易版本的进程池
linux·运维·服务器
自信不孤单2 小时前
Linux线程安全
linux·多线程·条件变量·线程安全·同步··互斥
7yewh2 小时前
嵌入式知识点总结 Linux驱动 (七)-Linux驱动常用函数 uboot命令 bootcmd bootargs get_part env_get
linux·arm开发·驱动开发·mcu·物联网·硬件工程
小白也有IT梦3 小时前
Bash 基础与进阶实践指南
linux·bash
Bai_Yin3 小时前
leetcode 844 比较含退格的字符串
linux·算法·leetcode
Linux运维老纪3 小时前
windows部署deepseek之方法(The Method of Deploying DeepSeek on Windows)
linux·人工智能·分布式·云原生·运维开发·devops
AlenTech3 小时前
Ubuntu 系统,如何使用双Titan V跑AI
linux·人工智能·ubuntu
Future_yzx3 小时前
Linux系统上安装与配置 MySQL( CentOS 7 )
linux·数据库·mysql
x66ccff4 小时前
【linux】Linux 常见目录特性、权限和功能
linux·服务器·php