学习了
有谁在楼主的基础上,创建个UI版本的来呀?给懒得打那些命令的人一个福利。
把这个脚本喂给Ai 几次后最终是这样
#!/bin/bash
增强版 ostree 快照管理脚本 v1.6
最后更新: 2025-09-26
功能: 自动创建/验证/清理系统快照,支持显示快照列表
===== 配置区域 =====
declare -r LOG_FILE="/var/log/ostree-snapshots.log"
declare -ri KEEP_SNAPSHOTS=3
declare -r LOCK_FILE="/var/run/ostree-snapshot.lock"
declare -r SNAPSHOT_PREFIX="Auto"
===================
初始化严格模式
set -euo pipefail
trap 'log "ERROR: 脚本异常终止"; exit 1' ERR
export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
显示帮助信息
show_help() {
cat << EOF
用法: $(basename "$0") [选项]
选项:
-l, --list 显示所有快照列表
-h, --help 显示此帮助信息
无参数 执行默认操作(创建当日快照并清理旧快照)
功能:
自动管理系统快照,包括创建每日快照、清理旧快照,
并可查看当前系统中的所有快照信息。
EOF
}
日志记录函数
log() {
local log\_entry="[\$(date '+%Y-%m-%d %H:%M:%S')] \$1"
echo "\$log\_entry" | tee -a "\$LOG\_FILE"
}
获取活跃用户列表
get_active_users() {
who | awk '{print \$1}' | sort -u | while read -r user; do
if loginctl show-user "\$user" | grep -q 'IdleHint=no'; then
echo "\$user"
fi
done
}
发送桌面通知
notify_users() {
local status=\$1
local message=\$2
while read -r user; do
local bus\_path="/run/user/\$(id -u "\$user")/bus"
[ -S "\$bus\_path" ] || continue
case "\$status" in
success)
sudo -u "\$user" DBUS\_SESSION\_BUS\_ADDRESS="unix:path=\$bus\_path" \\
notify-send -t 5000 -i dialog-ok "系统快照" "\$message"
;;
failure)
sudo -u "\$user" DBUS\_SESSION\_BUS\_ADDRESS="unix:path=\$bus\_path" \\
notify-send -t 10000 -i dialog-error "系统快照" "\$message"
;;
info)
sudo -u "\$user" DBUS\_SESSION\_BUS\_ADDRESS="unix:path=\$bus\_path" \\
notify-send -t 3000 -i dialog-information "系统快照" "\$message"
;;
esac
done < <(get\_active\_users)
}
显示快照列表
list_snapshots() {
echo "==================== 系统快照列表 ===================="
deepin-immutable-ctl snapshot list
# 统计自动快照数量
local snapshot\_list=\$(deepin-immutable-ctl snapshot list | tail -n +2)
local -a auto\_snapshots=()
while IFS= read -r line; do
local snap\_name=\$(echo "\$line" | awk '{print \$2}')
if [[ "\$snap\_name" == "\${SNAPSHOT\_PREFIX}-"\* ]]; then
auto\_snapshots+=("\$line")
fi
done <<< "\$snapshot\_list"
local total\_count=\$(echo "\$snapshot\_list" | wc -l)
local auto\_count=\${#auto\_snapshots[@]}
local manual\_count=\$((total\_count - auto\_count))
echo -e "\\n统计信息:"
echo " 总快照数: \$total\_count"
echo " 自动创建的快照数: \$auto\_count"
echo " 手动创建的快照数: \$manual\_count"
echo " 配置保留自动快照数: \$KEEP\_SNAPSHOTS"
echo "======================================================"
}
创建当日快照
create_daily_snapshot() {
local date\_stamp=\$(date +%Y%m%d)
local timestamp=\$(date +%Y%m%d-%H%M%S)
local snap\_name="\${SNAPSHOT\_PREFIX}-\${timestamp}"
local snap\_desc="每日快照-\$(date +%F)"
# 检查当日快照是否存在
if deepin-immutable-ctl snapshot list | grep -q "\${SNAPSHOT\_PREFIX}-\${date\_stamp}"; then
log "INFO: 当日快照已存在,跳过创建"
return 3 # 特殊返回码表示跳过
fi
# 创建新快照
log "创建快照: \${snap\_name} (\${snap\_desc})"
if ! deepin-immutable-ctl snapshot create "\$snap\_name" "\$snap\_desc"; then
log "ERROR: 快照创建命令执行失败"
return 1
fi
# 验证快照是否创建成功
if deepin-immutable-ctl snapshot list | grep -q "\$snap\_name"; then
log "SUCCESS: 快照创建成功"
return 0
else
log "CRITICAL: 快照创建后验证失败"
return 2
fi
}
清理旧快照
clean_old_snapshots() {
log "开始清理旧快照 (保留最新 \${KEEP\_SNAPSHOTS} 个)"
# 获取快照列表(跳过标题行)
local snapshot\_list=\$(deepin-immutable-ctl snapshot list | tail -n +2)
if [ -z "\$snapshot\_list" ]; then
log "INFO: 快照列表为空,无需清理"
return
fi
# 提取自动快照
local -a auto\_snapshots=()
while IFS= read -r line; do
# 提取快照名称(第二列)
local snap\_name=\$(echo "\$line" | awk '{print \$2}')
# 检查是否以 SNAPSHOT\_PREFIX 开头
if [[ "\$snap\_name" == "\${SNAPSHOT\_PREFIX}-"\* ]]; then
auto\_snapshots+=("\$line")
fi
done <<< "\$snapshot\_list"
local total\_count=\${#auto\_snapshots[@]}
if (( total\_count == 0 )); then
log "INFO: 没有自动快照,无需清理"
return
fi
# 计算需要删除的数量
local delete\_count=\$((total\_count - KEEP\_SNAPSHOTS))
if (( delete\_count <= 0 )); then
log "INFO: 无需删除快照 (当前 \${total\_count} 个自动快照)"
return
fi
log "计划删除 \${delete\_count} 个旧快照 (总共 \${total\_count} 个自动快照)"
# 按时间排序(第四列是日期时间)
mapfile -t sorted\_snapshots < <(printf "%s\\n" "\${auto\_snapshots[@]}" | sort -k4)
# 删除最早创建的快照
for (( i=0; i local snap\_line="\${sorted\_snapshots[\$i]}"
local snap\_id=\$(echo "\$snap\_line" | awk '{print \$1}')
local snap\_name=\$(echo "\$snap\_line" | awk '{print \$2}')
log "删除旧快照: \${snap\_name} (ID: \${snap\_id})"
if deepin-immutable-ctl snapshot delete "\$snap\_id"; then
log "SUCCESS: 成功删除快照"
else
log "WARNING: 删除快照失败"
fi
done
log "清理完成: 删除了 \${delete\_count} 个旧快照"
}
主控制流程
main() {
# 处理命令行参数
if [[ \$# -gt 0 ]]; then
case "\$1" in
-l|--list)
list\_snapshots
exit 0
;;
-h|--help)
show\_help
exit 0
;;
\*)
echo "错误: 未知选项 '\$1'"
show\_help
exit 1
;;
esac
fi
log "=== 启动快照任务 ==="
# 检查文件锁
if [[ -e "\$LOCK\_FILE" ]]; then
lock\_pid=\$(cat "\$LOCK\_FILE" 2>/dev/null)
if ps -p "\$lock\_pid" &>/dev/null; then
log "WARNING: 上一个任务仍在运行 (PID \$lock\_pid),跳过本次执行"
exit 0
else
log "清理过期的锁文件"
rm -f "\$LOCK\_FILE"
fi
fi
# 获取锁
echo \$\$ > "\$LOCK\_FILE"
trap 'rm -f "\$LOCK\_FILE"; log "清理锁文件"' EXIT
# 快照创建状态
local create\_status=0
create\_daily\_snapshot || create\_status=\$?
# 清理旧快照(无论创建是否成功)
clean\_old\_snapshots
# 通知用户
case \$create\_status in
0)
notify\_users "success" "系统快照创建成功"
log "=== 快照任务完成 ==="
exit 0
;;
1)
notify\_users "failure" "快照创建命令执行失败"
log "ERROR: === 快照任务失败 ==="
exit 1
;;
2)
notify\_users "failure" "快照创建后验证失败"
log "ERROR: === 快照任务失败 ==="
exit 1
;;
3)
notify\_users "info" "当日快照已存在,已跳过创建"
log "=== 快照任务完成 (已跳过创建) ==="
exit 0
;;
\*)
notify\_users "failure" "快照任务出现未知错误 (状态码: \$create\_status)"
log "ERROR: === 快照任务出现未知错误 ==="
exit 1
;;
esac
}
启动主程序
main "$@"
把这个脚本喂给Ai 几次后最终是这样
#!/bin/bash
增强版 ostree 快照管理脚本 v1.6
最后更新: 2025-09-26
功能: 自动创建/验证/清理系统快照,支持显示快照列表
===== 配置区域 =====
declare -r LOG_FILE="/var/log/ostree-snapshots.log"
declare -ri KEEP_SNAPSHOTS=3
declare -r LOCK_FILE="/var/run/ostree-snapshot.lock"
declare -r SNAPSHOT_PREFIX="Auto"
===================
初始化严格模式
set -euo pipefail
trap 'log "ERROR: 脚本异常终止"; exit 1' ERR
export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
显示帮助信息
show_help() {
cat << EOF
用法: $(basename "$0") [选项]
选项:
-l, --list 显示所有快照列表
-h, --help 显示此帮助信息
无参数 执行默认操作(创建当日快照并清理旧快照)
功能:
自动管理系统快照,包括创建每日快照、清理旧快照,
并可查看当前系统中的所有快照信息。
EOF
}
日志记录函数
log() {
local log\_entry="[\$(date '+%Y-%m-%d %H:%M:%S')] \$1"
echo "\$log\_entry" | tee -a "\$LOG\_FILE"
}
获取活跃用户列表
get_active_users() {
who | awk '{print \$1}' | sort -u | while read -r user; do
if loginctl show-user "\$user" | grep -q 'IdleHint=no'; then
echo "\$user"
fi
done
}
发送桌面通知
notify_users() {
local status=\$1
local message=\$2
while read -r user; do
local bus\_path="/run/user/\$(id -u "\$user")/bus"
[ -S "\$bus\_path" ] || continue
case "\$status" in
success)
sudo -u "\$user" DBUS\_SESSION\_BUS\_ADDRESS="unix:path=\$bus\_path" \\
notify-send -t 5000 -i dialog-ok "系统快照" "\$message"
;;
failure)
sudo -u "\$user" DBUS\_SESSION\_BUS\_ADDRESS="unix:path=\$bus\_path" \\
notify-send -t 10000 -i dialog-error "系统快照" "\$message"
;;
info)
sudo -u "\$user" DBUS\_SESSION\_BUS\_ADDRESS="unix:path=\$bus\_path" \\
notify-send -t 3000 -i dialog-information "系统快照" "\$message"
;;
esac
done < <(get\_active\_users)
}
显示快照列表
list_snapshots() {
echo "==================== 系统快照列表 ===================="
deepin-immutable-ctl snapshot list
# 统计自动快照数量
local snapshot\_list=\$(deepin-immutable-ctl snapshot list | tail -n +2)
local -a auto\_snapshots=()
while IFS= read -r line; do
local snap\_name=\$(echo "\$line" | awk '{print \$2}')
if [[ "\$snap\_name" == "\${SNAPSHOT\_PREFIX}-"\* ]]; then
auto\_snapshots+=("\$line")
fi
done <<< "\$snapshot\_list"
local total\_count=\$(echo "\$snapshot\_list" | wc -l)
local auto\_count=\${#auto\_snapshots[@]}
local manual\_count=\$((total\_count - auto\_count))
echo -e "\\n统计信息:"
echo " 总快照数: \$total\_count"
echo " 自动创建的快照数: \$auto\_count"
echo " 手动创建的快照数: \$manual\_count"
echo " 配置保留自动快照数: \$KEEP\_SNAPSHOTS"
echo "======================================================"
}
创建当日快照
create_daily_snapshot() {
local date\_stamp=\$(date +%Y%m%d)
local timestamp=\$(date +%Y%m%d-%H%M%S)
local snap\_name="\${SNAPSHOT\_PREFIX}-\${timestamp}"
local snap\_desc="每日快照-\$(date +%F)"
# 检查当日快照是否存在
if deepin-immutable-ctl snapshot list | grep -q "\${SNAPSHOT\_PREFIX}-\${date\_stamp}"; then
log "INFO: 当日快照已存在,跳过创建"
return 3 # 特殊返回码表示跳过
fi
# 创建新快照
log "创建快照: \${snap\_name} (\${snap\_desc})"
if ! deepin-immutable-ctl snapshot create "\$snap\_name" "\$snap\_desc"; then
log "ERROR: 快照创建命令执行失败"
return 1
fi
# 验证快照是否创建成功
if deepin-immutable-ctl snapshot list | grep -q "\$snap\_name"; then
log "SUCCESS: 快照创建成功"
return 0
else
log "CRITICAL: 快照创建后验证失败"
return 2
fi
}
清理旧快照
clean_old_snapshots() {
log "开始清理旧快照 (保留最新 \${KEEP\_SNAPSHOTS} 个)"
# 获取快照列表(跳过标题行)
local snapshot\_list=\$(deepin-immutable-ctl snapshot list | tail -n +2)
if [ -z "\$snapshot\_list" ]; then
log "INFO: 快照列表为空,无需清理"
return
fi
# 提取自动快照
local -a auto\_snapshots=()
while IFS= read -r line; do
# 提取快照名称(第二列)
local snap\_name=\$(echo "\$line" | awk '{print \$2}')
# 检查是否以 SNAPSHOT\_PREFIX 开头
if [[ "\$snap\_name" == "\${SNAPSHOT\_PREFIX}-"\* ]]; then
auto\_snapshots+=("\$line")
fi
done <<< "\$snapshot\_list"
local total\_count=\${#auto\_snapshots[@]}
if (( total\_count == 0 )); then
log "INFO: 没有自动快照,无需清理"
return
fi
# 计算需要删除的数量
local delete\_count=\$((total\_count - KEEP\_SNAPSHOTS))
if (( delete\_count <= 0 )); then
log "INFO: 无需删除快照 (当前 \${total\_count} 个自动快照)"
return
fi
log "计划删除 \${delete\_count} 个旧快照 (总共 \${total\_count} 个自动快照)"
# 按时间排序(第四列是日期时间)
mapfile -t sorted\_snapshots < <(printf "%s\\n" "\${auto\_snapshots[@]}" | sort -k4)
# 删除最早创建的快照
for (( i=0; i local snap\_line="\${sorted\_snapshots[\$i]}"
local snap\_id=\$(echo "\$snap\_line" | awk '{print \$1}')
local snap\_name=\$(echo "\$snap\_line" | awk '{print \$2}')
log "删除旧快照: \${snap\_name} (ID: \${snap\_id})"
if deepin-immutable-ctl snapshot delete "\$snap\_id"; then
log "SUCCESS: 成功删除快照"
else
log "WARNING: 删除快照失败"
fi
done
log "清理完成: 删除了 \${delete\_count} 个旧快照"
}
主控制流程
main() {
# 处理命令行参数
if [[ \$# -gt 0 ]]; then
case "\$1" in
-l|--list)
list\_snapshots
exit 0
;;
-h|--help)
show\_help
exit 0
;;
\*)
echo "错误: 未知选项 '\$1'"
show\_help
exit 1
;;
esac
fi
log "=== 启动快照任务 ==="
# 检查文件锁
if [[ -e "\$LOCK\_FILE" ]]; then
lock\_pid=\$(cat "\$LOCK\_FILE" 2>/dev/null)
if ps -p "\$lock\_pid" &>/dev/null; then
log "WARNING: 上一个任务仍在运行 (PID \$lock\_pid),跳过本次执行"
exit 0
else
log "清理过期的锁文件"
rm -f "\$LOCK\_FILE"
fi
fi
# 获取锁
echo \$\$ > "\$LOCK\_FILE"
trap 'rm -f "\$LOCK\_FILE"; log "清理锁文件"' EXIT
# 快照创建状态
local create\_status=0
create\_daily\_snapshot || create\_status=\$?
# 清理旧快照(无论创建是否成功)
clean\_old\_snapshots
# 通知用户
case \$create\_status in
0)
notify\_users "success" "系统快照创建成功"
log "=== 快照任务完成 ==="
exit 0
;;
1)
notify\_users "failure" "快照创建命令执行失败"
log "ERROR: === 快照任务失败 ==="
exit 1
;;
2)
notify\_users "failure" "快照创建后验证失败"
log "ERROR: === 快照任务失败 ==="
exit 1
;;
3)
notify\_users "info" "当日快照已存在,已跳过创建"
log "=== 快照任务完成 (已跳过创建) ==="
exit 0
;;
\*)
notify\_users "failure" "快照任务出现未知错误 (状态码: \$create\_status)"
log "ERROR: === 快照任务出现未知错误 ==="
exit 1
;;
esac
}
启动主程序
main "$@"
之前我还搞过一个蓝牙连手机,断连后自动锁屏的脚本,当时也是发给ai让优化来着,结果规范是规范了,但也变得非常复杂了 。
就本次这个脚本来看,确实给优化复杂了。
学习了,谢谢分享。
学习了,谢谢分享。
这个dialog-ok和dialog-error挺好,我觉得我可以照这个改一下
666,太棒了
Popular Events
More
背景描述
之前我在使用btrfs的时候,参考timeshift的思路,自己写了个自动btrfs快照的脚本。
现在换到v25系统了,把原来的脚本改了下,改成了自动创建ostree快照的脚本。
本次抛砖分享下。
整体思路
1、使用root的定时任务,执行创建快照的脚本。
2、每小时执行一次,如果已有当天的快照,则不再创建新快照,否则创建一个以日期时间命名的快照。
3、创建成功或失败,均弹出一次通知信息,以方便确认是否成功创建快照。
4、创建快照成功后,删除旧快照,只留存3个“自动”快照(不删除手工创建的快照)。
5、把执行信息输出个日志文件,方便创建失败时进行排查。
具体实现
root用户的定时任务:
脚本内容(deepin-daily-snapshot.sh):
相关命令
列出快照:
创建快照:
回滚快照:
删除快照: