一、跨平台脚本文件对比

常见脚本类型

平台 脚本类型 解释器 文件扩展名
Linux / Unix Bourne Shell sh .sh
Bash bash .bash / .sh
Zsh zsh .zsh
Windows 原生 批处理 cmd.exe .bat / .cmd
PowerShell powershell.exe .ps1
Windows 兼容层 Bash (WSL/Git Bash) bash (通过 WSL 或模拟) .sh

权限差异

⚠️ 重要提示:脚本文件以管理员身份运行普通用户身份运行有本质区别,主要体现在:

  • 权限级别:系统文件访问、注册表修改、服务管理等操作
  • 可执行的操作范围:网络配置、驱动安装、系统设置等
  • 安全风险:管理员权限下的错误操作可能影响整个系统

二、Linux/Unix Shell 脚本

1. Shebang 声明

Shebang(#!)必须位于脚本第一行,告诉系统使用哪个解释器执行脚本:

1
2
3
4
#!/bin/bash              # 使用系统的 /bin/bash(固定路径)
#!/usr/bin/env bash # 推荐!自动在 PATH 中查找 bash(可移植性更好)
#!/bin/sh # 使用 POSIX 标准 shell(可能是 dash 或 bash)
#!/usr/bin/env python3 # Python 脚本示例

最佳实践:使用 #!/usr/bin/env <interpreter> 提高跨系统兼容性。

2. 赋予执行权限

1
2
3
4
5
6
7
8
9
10
# 查看文件权限
ls -l script.sh

# 赋予所有用户执行权限
chmod +x script.sh

# 更精细的权限控制
chmod 755 script.sh # rwxr-xr-x(所有者可读写执行,其他人可读执行)
chmod u+x script.sh # 仅为所有者添加执行权限
chmod 777 script.sh # 赋予最高权限 7=读(4)+写(2)+执行(1) 三个7: 所有者u|所属组g|其他用户o

3. 执行脚本的方式

1
2
3
4
5
6
7
8
9
10
11
# 方式1:直接执行(需要执行权限和 shebang)
./script.sh

# 方式2:显式指定解释器(不需要执行权限)
bash script.sh
sh script.sh

# 方式3:在当前 shell 中执行(会影响当前环境变量)
source script.sh
. script.sh

⚠️ 重要:当脚本中某条命令执行失败时,默认行为是继续执行下一行,而不是停止或回滚。

1
2
3
4
#!/bin/bash
echo "步骤 1"
false # 这条命令会失败(返回非零退出码)
echo "步骤 2" # 但仍会执行这一行!

4. 语法检查

1
2
3
4
5
6
7
# 仅检查语法,不执行脚本
bash -n script.sh
# 调试模式执行(显示每条命令)
bash -x script.sh
# 脚本内开启调试
set -x # 开启命令跟踪
set +x # 关闭命令跟踪

5. 注释语法

写法 是否合法 说明
# 这是注释 标准单行注释
echo "text" # 注释 行尾注释(# 前建议加空格)
#! /bin/bash Shebang(必须在第一行)
: '多行注释' 使用 : 命令和单引号实现多行注释

多行注释示例

1
2
3
4
5
: "
这是多行注释
可以写多行内容
不会被执行
"

6. Python运行脚本

basic

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1.直接执行
# 前提:Python文件第一行有 #!/usr/bin/env python3 (需要shebang)
./train.py --参数1 值1 --参数2 值2

# 2.使用不同的python解释器
python train.py # 系统默认Python
python3 train.py # 明确使用Python3
python3.8 train.py # 指定特定版本
/path/to/python train.py # 使用绝对路径

# 3.模块方式执行(如果train.py是一个模块,即其中有相对导入)
python -m train # 从模块路径执行
python -m package.train # 包内的模块

torchrun

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash

# 可配置参数(通过环境变量覆盖)
DATA_DIR=${DATA_DIR:-"/home/data/image_classify/data_broken/demage_package_data_build20260114/"}
OUTPUT_DIR=${OUTPUT_DIR:-"./outputs/classification_vitb16/broken/0115/realdata"}

# 设置CUDA设备
export CUDA_VISIBLE_DEVICES="4,5,6,7"

# 执行训练
torchrun --nproc_per_node=4 --master_port=29502 train_classification_vitb16_broken.py \
--data_dir "$DATA_DIR" \
--output_dir "$OUTPUT_DIR" \
--use_list_file \
--list_file_name "train_list.txt" \
--pretrained_weights "dinov3_vitb16_pretrain_lvd1689m-73cec8be.pth" \
--epochs 200 \
--batch_size 256 \
--lr 1e-3 \
--weight_decay 1e-4 \
--seed 42 \
--device "auto" \
--distributed \
--save_every 20

accelerate launch

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
# 设置全局环境变量 
export MODEL_PATH="/home/mvb/.cache/huggingface/hub/models--SG161222--Realistic_Vision_V5.1_noVAE/snapshots/1e9f017a7b1eaefb63a1900ea6c5953d2739fd21"
export OUTPUT_DIR="./trained_models/damaged_pkgs_sd5.1_lora0104_1"
export DATASET_PATH="/home/data/image_classify/data_broken/enhense_broken_resize_pad" # "/home/projects/wwj/adapter/damaged_pkgs/train"
export CACHE_DIR="/home/projects/wwj/tmp/cache"
export CUDA_VISIBLE_DEVICES="4,5"

accelerate launch --num_processes=2 train_t2I_lora.py \
--mixed_precision="no" \
--pretrained_model_name_or_path=${MODEL_PATH} \
--train_data_dir=${DATASET_PATH} \
--cache_dir=${CACHE_DIR} \
--image_column="image_filename" \
--caption_column="text" \
--dataloader_num_workers=6 \
--resolution=512 --center_crop --random_flip \
--train_batch_size=2 \
--gradient_accumulation_steps=4 \
--max_train_steps=2500 \
--learning_rate=1e-05 \
--max_grad_norm=1 \
--lr_scheduler="constant" --lr_warmup_steps=0 \
--output_dir=${OUTPUT_DIR} \
--checkpointing_steps=500 \
--validation_epochs=2 \
--rank 12 \
--dropout 0.1 \
--validation_prompt="a single express box with moderate damages." \
--seed=1337

deepspeed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash

# 可配置参数(通过环境变量覆盖)
DATA_DIR=${DATA_DIR:-"/home/data/image_classify/data_broken/demage_package_data_build20260114/"}
OUTPUT_DIR=${OUTPUT_DIR:-"./outputs/classification_vitb16/broken/0115/realdata"}

# 设置CUDA设备
export CUDA_VISIBLE_DEVICES="4,5,6,7"

# 执行训练(使用deepspeed)
deepspeed --num_gpus 4 --master_port 29500 train_classification_vitb16_broken.py \
--data_dir "$DATA_DIR" \
--output_dir "$OUTPUT_DIR" \
--use_list_file \
--list_file_name "train_list.txt" \
--pretrained_weights "dinov3_vitb16_pretrain_lvd1689m-73cec8be.pth" \
--epochs 200 \
--batch_size 256 \
--lr 1e-3 \
--weight_decay 1e-4 \
--seed 42 \
--device "auto" \
--distributed \
--save_every 20

模型训练平台特定命令

1
2
3
4
5
6
7
8
# Weights & Biases
wandb train.py --epochs=10

# Hugging Face Hub
huggingface-cli train path/to/train.py

# Amazon SageMaker
python -m sagemaker.train --script train.py

三、Windows 批处理脚本

1. @echo off 命令详解

@echo off 是批处理脚本中最常见的第一行命令

1
2
3
4
5
6
@echo off
REM 这是注释

echo 正在执行任务...
dir C:\
pause

作用说明

  • echo off:关闭命令回显,后续命令执行时只显示输出结果,不显示命令本身
  • @:让 echo off 这条命令本身也不回显
  • 默认状态echo on(会显示每条命令 + 执行结果)

2. 常用批处理命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@echo off
REM 或 :: 都可以用作注释

REM 变量设置
set VAR=value
echo %VAR%

REM 条件判断
if exist "file.txt" (
echo 文件存在
) else (
echo 文件不存在
)

REM 循环
for %%i in (*.txt) do echo %%i

REM 暂停(等待用户按键)
pause

四、Shell 解释器家族

1. Bourne Shell 家族

Shell 全称 特点 推荐场景
sh Bourne Shell 最原始的 Unix shell ❌ 已淘汰(仅作为标准参考)
bash Bourne-Again SHell sh 的超集,功能强大 Linux 默认,脚本编写首选
dash Debian Almquist Shell sh 的轻量实现,执行速度快 ✅ Ubuntu/Debian 的 /bin/sh
ksh Korn Shell sh 超集,早期企业级选择 ⚠️ 少数企业使用
zsh Z Shell bash 超集,交互体验最佳 macOS 10.15+ 默认

2. C Shell 家族(不推荐用于脚本)

Shell 特点 现状
csh C 语言风格语法 脚本编写强烈不推荐
tcsh csh 增强版 ⚠️ 仅限交互使用

📖 延伸阅读《Csh Programming Considered Harmful》 详细解释了为何不应该用 csh 写脚本。


五、Terminal Multiplexer(tmux,终端复用器)

👉 一个终端里开很多“窗口/面板”,断线了还能继续

概念 类比
session 一个工作空间
window 一个 tab
pane tab 里的分屏

0️⃣安装

1
2
sudo apt update
sudo apt install tmux

1️⃣ 新建 session

1
2
tmux
tmux new -s mysession #带名字

2️⃣ tmux 的“前缀键”所有 tmux 快捷键 = 先按前缀键 + 松开后再按功能键

默认前缀键是:

1
Ctrl + b

3️⃣ 分屏(pane)

操作 快捷键
横向分屏 Ctrl+b "
纵向分屏 Ctrl+b %
切换面板 Ctrl+b 上下箭头
关闭当前面板 Ctrl+b x

4️⃣ 窗口(window)

操作 快捷键
新建窗口 Ctrl+b c
切换下一个/上一个窗口 Ctrl+b n / p
指定窗口 Ctrl+b 数字
关闭窗口 exit
重命名当前窗口 Ctrl+b , <newName>

5️⃣ 会话(session)

操作 命令
查看所有会话 tmux ls
进入会话 tmux attach -t <mysession> tmux a -t <mysession>
离开会话(不关闭) Ctrl+b d
tmux中查看会话 Ctrl+b s
关闭会话 tmux kill-session -t <mysession>
重命名会话 tmux rename-session -t <old> <new>
进入命令行模式 Ctrl+b :
进入复制模式 可查看历史缓冲区 Ctrl + b [

⚠️ SSH 断了 ≠ tmux 断了
重新连上服务器:

1
tmux attach -t mysession

6️⃣修改tmux 配置

配置文件:

1
~/.tmux.conf
1
2
3
4
5
6
7
8
9
10
11
# 临时:先Ctrl+b :
# 永久:vim ~/.tmux.conf 写入配置文件
# 开启鼠标
set -g mouse on # Shift + 鼠标滚轮可查看历史缓冲区

# 快速重载配置
bind r source-file ~/.tmux.conf \; display "Reloaded!"

# 面板编号从 1 开始
set -g base-index 1
setw -g pane-base-index 1

生效:

1
tmux source ~/.tmux.conf