基于dialog的Calibre书籍添加Bash脚本问题求助
Calibre书籍批量添加脚本问题排查与修复
以下是针对你的Bash脚本问题的逐一解决方案:
问题1:首次选择M进入form_data正常,其他子菜单后再选M失效
原因
form_data函数中修改了全局的IFS(内部字段分隔符)为$'\n'但未恢复原值,导致后续dialog的输出解析异常。
修复代码
function form_data() { local auth="" serie="" tag="" ind="1" # 保存原始IFS local OLD_IFS="$IFS" IFS=$'\n' echo "form data" exec 3>&1 VALUES=($(dialog --clear --ok-label "Submit" \ --backtitle "Calibre" \ --title "Manager" \ --form "Add a book" \ 15 50 0 \ "Author's name:" 1 1 "$auth" 1 20 30 0 \ "Serie's name:" 2 1 "$serie" 2 20 30 0 \ "Tag:" 3 1 "$tag" 3 20 30 0 \ "Serie's index (int):" 4 1 "$ind" 4 20 30 0 \ 2>&1 1>&3)) exec 3>&- # 恢复原始IFS IFS="$OLD_IFS" # 直接返回,由主循环重新显示菜单 }
问题2:case语句启动报错,改用if语句
原因
大概率是case语法不规范(变量未加引号、分支格式错误),以下是正确的case写法:
function main_menu(){ local MENU=$(dialog --clear --title "Calibre" \ --backtitle "Add Books" \ --menu "What to do ?" \ 0 0 0 "C" "Choose a book or a folder" "M" "Enter metadata infos" "L" "Add selected Book(s)" "D" "Change default Directory for books" "E" "Exit" \ 2>&1 >/dev/tty) # 处理用户按下Cancel的情况(MENU为空) if [ -z "$MENU" ]; then return fi case "$MENU" in "C") select=$(file_selector "$mnt") ;; "M") form_data ;; "L") if [ -d "$select" ]; then add_folder "$select" elif [ -f "$select" ]; then # 修复原代码中$file的错误,应为$select if [[ "$select" == *.cbz || "$select" == *.pdf ]]; then add_book "$select" else error "Books should have extensions .cbz or .pdf" fi else error "No file or folder selected" fi ;; "D") NEWDIR=$(file_selector "$mnt") # 将新目录赋值给mnt,确保下次生效 mnt="$NEWDIR" ;; "E") exit 0 ;; esac }
额外说明
- 所有变量引用加双引号,避免空格导致的参数拆分问题
- 增加用户按Cancel时的处理逻辑
问题3:error信息对话框无法正常工作
原因
$1未加双引号,错误信息含空格时会被拆分,导致dialog参数错误- 递归调用
main_menu会导致函数栈嵌套过深,建议用主循环替代
修复代码
function error() { dialog --clear --title "Error" --msgbox "$1" 10 50 # dialog会等待用户点击OK,无需sleep # 直接返回,由主循环重新显示菜单 } # 主脚本入口用循环代替递归 while true; do main_menu done
问题4:form_data提交后调用main_menu是否正确
结论
递归调用main_menu是错误的,会导致函数栈不断累积最终溢出。正确做法:
- 主脚本用
while true循环反复调用main_menu - 所有子函数(form_data、add_folder等)执行完成后直接返回,由主循环重新显示主菜单
调整后的主脚本结构
#!/bin/bash # 初始化全局变量 mnt="/path/to/default/directory" select="" VALUES=() # 此处放置所有函数定义... # 主循环 while true; do main_menu done
问题5:实现dialog进度条
方案1:自定义进度条(适用于calibredb无进度输出的情况)
自己计算文件数量,逐个添加并更新进度:
function add_folder() { local folder="$1" # 仅筛选cbz/pdf文件 local book_list=($(find "$folder" -maxdepth 1 -type f \( -name "*.cbz" -o -name "*.pdf" \))) local total=${#book_list[@]} local current=0 # 初始化进度条 dialog --clear --title "Adding Books" --gauge "Starting..." 10 60 0 for book in "${book_list[@]}"; do current=$((current+1)) local progress=$((current*100/total)) # 更新进度条内容 echo "$progress" | dialog --clear --title "Adding Books" --gauge "Adding: $(basename "$book")" 10 60 0 # 执行添加命令,屏蔽输出避免干扰进度条 calibredb add -a "${VALUES[0]}" -s "${VALUES[1]}" -T "${VALUES[2]}" -S "$current" "$book" --with-library /home/gregory/books >/dev/null 2>&1 done # 完成后提示 dialog --clear --title "Done" --msgbox "Successfully added $total books" 10 50 }
方案2:使用进度框(适用于calibredb有详细输出的情况)
如果calibredb add有日志输出,直接将输出传给dialog:
function add_folder() { local folder="$1" calibredb add -a "${VALUES[0]}" -s "${VALUES[1]}" -T "${VALUES[2]}" --with-library /home/gregory/books "$folder" 2>&1 | dialog --clear --title "Adding Books" --progressbox 20 60 dialog --clear --title "Done" --msgbox "Add operation completed" 10 50 }
原代码额外修复
- 原循环变量
i未初始化,数组索引从0开始,直接用数组遍历更可靠 - 增加文件类型过滤,避免无效文件被添加
内容的提问来源于stack exchange,提问作者rhadamanthe
相关产品推荐
相关产品推荐

