This repository has been archived on 2026-08-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
openclaw/cron/scripts/zq-file.sh
T

460 lines
13 KiB
Bash
Executable File

#!/bin/bash
# 工作区文件操作脚本
# 用法:
# zq-file.sh read <文件路径> 读取文件内容
# zq-file.sh write <文件路径> <内容> 写入/覆盖文件
# zq-file.sh append <文件路径> <内容> 追加内容到文件末尾
# zq-file.sh prepend <文件路径> <内容> 在文件开头插入内容
# zq-file.sh replace <文件路径> <旧内容> <新内容> 替换文本(精确匹配)
# zq-file.sh replace-all <文件路径> <旧内容> <新内容> 替换所有匹配
# zq-file.sh remove <文件路径> <要删除的内容> 删除特定文本
# zq-file.sh insert-before <文件路径> <标记行> <内容> 在某行之前插入
# zq-file.sh insert-after <文件路径> <标记行> <内容> 在某行之后插入
# zq-file.sh delete <文件路径> 删除文件
# zq-file.sh new <文件路径> <内容> 新建文件
#
# 脚本会自动执行:
# 1. 从NAS同步到本地
# 2. 执行操作
# 3. Git提交
# 4. 同步到NAS
set -e
ZQ_DIR="$HOME/work/zq"
NAS_REMOTE="nas-webdav:/home/Drive/工作区/张青/工作区/"
EXCLUDE_ARGS="--exclude .git/ --exclude .gitignore"
LOG_FILE="$HOME/work/zq-file.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
usage() {
cat << 'EOF'
工作区文件操作脚本
用法:
zq-file.sh read <文件路径> 读取文件内容
zq-file.sh write <文件路径> "内容" 写入/覆盖文件
zq-file.sh append <文件路径> "内容" 追加内容到文件末尾
zq-file.sh prepend <文件路径> "内容" 在文件开头插入内容
zq-file.sh replace <文件路径> "旧内容" "新内容" 替换文本(精确匹配,首次)
zq-file.sh replace-all <文件路径> "旧内容" "新内容" 替换所有匹配的文本
zq-file.sh remove <文件路径> "要删除的内容" 删除特定文本
zq-file.sh insert-before <文件路径> "标记行" "内容" 在标记行之前插入
zq-file.sh insert-after <文件路径> "标记行" "内容" 在标记行之后插入
zq-file.sh delete <文件路径> 删除文件
zq-file.sh new <文件路径> "内容" 新建文件
注意:
- 文件路径是相对于 ~/work/zq 的路径,或绝对路径
- 内容支持多行,用 $'\n' 表示换行,或使用 $'...\n...'
- replace/remove 操作会精确匹配文本(包括空格和换行)
- 操作会自动:从NAS同步 → 执行操作 → Git提交 → 同步到NAS
示例:
# 读取文件
zq-file.sh read 10.项目/README.md
# 写入内容
zq-file.sh write 00.收件箱/test.md "Hello World"
# 追加内容(支持多行)
zq-file.sh append 00.收件箱/01-速记本.md "- 新的速记"$'\n'"- 另一条"
# 在文件开头插入
zq-file.sh prepend 30.资源/notes.md "# 标题"
# 替换文本
zq-file.sh replace 10.项目/README.md "旧内容" "新内容"
# 替换多行文本
zq-file.sh replace 10.项目/README.md $'第一行\n第二行' $'新第一行\n新第二行'
# 删除特定文本
zq-file.sh remove 10.项目/README.md "要删除的行"
# 在某行之前插入
zq-file.sh insert-before 10.项目/README.md "## 章节" "这是新插入的内容"
# 在某行之后插入
zq-file.sh insert-after 10.项目/README.md "## 章节" "这是新插入的内容"
# 删除文件
zq-file.sh delete 40.归档/old-file.md
# 新建文件
zq-file.sh new 30.资源/new-note.md "# 新笔记"
EOF
}
# 确保在正确目录
cd "$ZQ_DIR" || { log "错误:无法进入 $ZQ_DIR"; exit 1; }
# 解析参数
ACTION="$1"
shift || { usage; exit 1; }
# 处理文件路径(支持相对路径和绝对路径)
resolve_path() {
local path="$1"
if [[ "$path" = /* ]]; then
# 绝对路径
echo "$path"
else
# 相对路径,基于 ~/work/zq
echo "$ZQ_DIR/$path"
fi
}
# 从NAS同步到本地
sync_from_nas() {
log "步骤1: 从NAS同步到本地..."
rclone sync "$NAS_REMOTE" "$ZQ_DIR/" $EXCLUDE_ARGS --log-level INFO >> "$LOG_FILE" 2>&1 || {
log "警告:从NAS同步失败,继续执行..."
}
log "同步完成"
}
# Git提交
git_commit() {
local message="$1"
log "步骤3: Git提交..."
git add -A >> "$LOG_FILE" 2>&1
git commit -m "$message" >> "$LOG_FILE" 2>&1 || log "没有变更需要提交"
git push origin main >> "$LOG_FILE" 2>&1 || log "警告:Git push失败"
}
# 同步到NAS
sync_to_nas() {
log "步骤4: 同步到NAS..."
rclone sync "$ZQ_DIR/" "$NAS_REMOTE" $EXCLUDE_ARGS --log-level INFO >> "$LOG_FILE" 2>&1 || {
log "错误:同步到NAS失败"
exit 1
}
log "同步完成"
}
# 执行操作
case "$ACTION" in
read)
FILE_PATH=$(resolve_path "$1")
REL_PATH="${FILE_PATH#$ZQ_DIR/}"
sync_from_nas
log "步骤2: 读取文件 $REL_PATH"
if [[ ! -f "$FILE_PATH" ]]; then
log "错误:文件不存在"
exit 1
fi
cat "$FILE_PATH"
log "完成!"
;;
write)
FILE_PATH=$(resolve_path "$1")
REL_PATH="${FILE_PATH#$ZQ_DIR/}"
CONTENT="$2"
sync_from_nas
log "步骤2: 写入文件 $REL_PATH"
mkdir -p "$(dirname "$FILE_PATH")"
printf '%s' "$CONTENT" > "$FILE_PATH"
git_commit "写入: $REL_PATH"
sync_to_nas
log "完成!"
;;
append)
FILE_PATH=$(resolve_path "$1")
REL_PATH="${FILE_PATH#$ZQ_DIR/}"
CONTENT="$2"
sync_from_nas
log "步骤2: 追加到文件 $REL_PATH"
if [[ ! -f "$FILE_PATH" ]]; then
log "错误:文件不存在"
exit 1
fi
printf '\n%s' "$CONTENT" >> "$FILE_PATH"
git_commit "追加: $REL_PATH"
sync_to_nas
log "完成!"
;;
prepend)
FILE_PATH=$(resolve_path "$1")
REL_PATH="${FILE_PATH#$ZQ_DIR/}"
CONTENT="$2"
sync_from_nas
log "步骤2: 在文件开头插入 $REL_PATH"
if [[ ! -f "$FILE_PATH" ]]; then
log "错误:文件不存在"
exit 1
fi
# 创建临时文件,先写入新内容,再写入原内容
TEMP_FILE=$(mktemp)
printf '%s\n' "$CONTENT" > "$TEMP_FILE"
cat "$FILE_PATH" >> "$TEMP_FILE"
mv "$TEMP_FILE" "$FILE_PATH"
git_commit "开头插入: $REL_PATH"
sync_to_nas
log "完成!"
;;
replace)
FILE_PATH=$(resolve_path "$1")
REL_PATH="${FILE_PATH#$ZQ_DIR/}"
OLD_TEXT="$2"
NEW_TEXT="$3"
sync_from_nas
log "步骤2: 替换文本 $REL_PATH"
if [[ ! -f "$FILE_PATH" ]]; then
log "错误:文件不存在"
exit 1
fi
# 检查旧文本是否存在
if ! grep -qF "$OLD_TEXT" "$FILE_PATH"; then
log "错误:未找到要替换的文本"
exit 1
fi
# 使用 Python 进行精确替换(只替换第一次匹配)
python3 << PYEOF
import sys
with open("$FILE_PATH", 'r', encoding='utf-8') as f:
content = f.read()
old_text = """$OLD_TEXT"""
new_text = """$NEW_TEXT"""
if old_text not in content:
print("错误:未找到要替换的文本", file=sys.stderr)
sys.exit(1)
# 只替换第一次出现
new_content = content.replace(old_text, new_text, 1)
with open("$FILE_PATH", 'w', encoding='utf-8') as f:
f.write(new_content)
PYEOF
git_commit "替换: $REL_PATH"
sync_to_nas
log "完成!"
;;
replace-all)
FILE_PATH=$(resolve_path "$1")
REL_PATH="${FILE_PATH#$ZQ_DIR/}"
OLD_TEXT="$2"
NEW_TEXT="$3"
sync_from_nas
log "步骤2: 替换所有匹配 $REL_PATH"
if [[ ! -f "$FILE_PATH" ]]; then
log "错误:文件不存在"
exit 1
fi
# 检查旧文本是否存在
if ! grep -qF "$OLD_TEXT" "$FILE_PATH"; then
log "错误:未找到要替换的文本"
exit 1
fi
# 使用 Python 进行全局替换
python3 << PYEOF
with open("$FILE_PATH", 'r', encoding='utf-8') as f:
content = f.read()
old_text = """$OLD_TEXT"""
new_text = """$NEW_TEXT"""
new_content = content.replace(old_text, new_text)
with open("$FILE_PATH", 'w', encoding='utf-8') as f:
f.write(new_content)
PYEOF
git_commit "替换全部: $REL_PATH"
sync_to_nas
log "完成!"
;;
remove)
FILE_PATH=$(resolve_path "$1")
REL_PATH="${FILE_PATH#$ZQ_DIR/}"
TEXT_TO_REMOVE="$2"
sync_from_nas
log "步骤2: 删除文本 $REL_PATH"
if [[ ! -f "$FILE_PATH" ]]; then
log "错误:文件不存在"
exit 1
fi
# 使用 Python 删除特定文本
python3 << PYEOF
import sys
with open("$FILE_PATH", 'r', encoding='utf-8') as f:
content = f.read()
text_to_remove = """$TEXT_TO_REMOVE"""
if text_to_remove not in content:
print("错误:未找到要删除的文本", file=sys.stderr)
sys.exit(1)
new_content = content.replace(text_to_remove, '')
with open("$FILE_PATH", 'w', encoding='utf-8') as f:
f.write(new_content)
PYEOF
git_commit "删除文本: $REL_PATH"
sync_to_nas
log "完成!"
;;
insert-before)
FILE_PATH=$(resolve_path "$1")
REL_PATH="${FILE_PATH#$ZQ_DIR/}"
MARKER="$2"
CONTENT="$3"
sync_from_nas
log "步骤2: 在标记行之前插入 $REL_PATH"
if [[ ! -f "$FILE_PATH" ]]; then
log "错误:文件不存在"
exit 1
fi
# 使用 Python 在标记行之前插入
python3 << PYEOF
import sys
with open("$FILE_PATH", 'r', encoding='utf-8') as f:
content = f.read()
marker = """$MARKER"""
new_content = """$CONTENT"""
if marker not in content:
print("错误:未找到标记行", file=sys.stderr)
sys.exit(1)
# 在第一次出现的标记之前插入
result = content.replace(marker, new_content + '\n' + marker, 1)
with open("$FILE_PATH", 'w', encoding='utf-8') as f:
f.write(result)
PYEOF
git_commit "前插: $REL_PATH"
sync_to_nas
log "完成!"
;;
insert-after)
FILE_PATH=$(resolve_path "$1")
REL_PATH="${FILE_PATH#$ZQ_DIR/}"
MARKER="$2"
CONTENT="$3"
sync_from_nas
log "步骤2: 在标记行之后插入 $REL_PATH"
if [[ ! -f "$FILE_PATH" ]]; then
log "错误:文件不存在"
exit 1
fi
# 使用 Python 在标记行之后插入
python3 << PYEOF
import sys
with open("$FILE_PATH", 'r', encoding='utf-8') as f:
content = f.read()
marker = """$MARKER"""
new_content = """$CONTENT"""
if marker not in content:
print("错误:未找到标记行", file=sys.stderr)
sys.exit(1)
# 在第一次出现的标记之后插入
result = content.replace(marker, marker + '\n' + new_content, 1)
with open("$FILE_PATH", 'w', encoding='utf-8') as f:
f.write(result)
PYEOF
git_commit "后插: $REL_PATH"
sync_to_nas
log "完成!"
;;
delete)
FILE_PATH=$(resolve_path "$1")
REL_PATH="${FILE_PATH#$ZQ_DIR/}"
sync_from_nas
log "步骤2: 删除文件 $REL_PATH"
if [[ ! -f "$FILE_PATH" ]]; then
log "错误:文件不存在"
exit 1
fi
trash "$FILE_PATH" 2>/dev/null || rm "$FILE_PATH"
git_commit "删除: $REL_PATH"
sync_to_nas
log "完成!"
;;
new)
FILE_PATH=$(resolve_path "$1")
REL_PATH="${FILE_PATH#$ZQ_DIR/}"
CONTENT="$2"
sync_from_nas
log "步骤2: 新建文件 $REL_PATH"
if [[ -f "$FILE_PATH" ]]; then
log "错误:文件已存在"
exit 1
fi
mkdir -p "$(dirname "$FILE_PATH")"
printf '%s' "$CONTENT" > "$FILE_PATH"
git_commit "新建: $REL_PATH"
sync_to_nas
log "完成!"
;;
-h|--help|help)
usage
;;
*)
log "错误:未知操作 '$ACTION'"
usage
exit 1
;;
esac