#!/bin/bash # (v9) 支持新格式:名称 # 说明 # 命令 interactive_mode() { local command_file="${1:-/Users/linbin/SynologyDrive/附件/590/cmd/my_commands}" local initial_query="${2:-}" # 使用临时文件来避免复杂的引号转义问题 local preview_script="/tmp/preview_$$" cat > "$preview_script" << 'EOF' #!/bin/bash command_file="$1" line_content="$2" # trim空格 name_part=$(echo "$line_content" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') # 从原文件中获取完整的行 full_line=$(grep -v "^#" "$command_file" | awk -F'#' -v name="$name_part" '{ first_field = $1 gsub(/^[[:space:]]+|[[:space:]]+$/, "", first_field) if (first_field == name) print $0 }' | head -1) if [ -n "$full_line" ]; then # 提取三部分:名称、说明、命令 name=$(echo "$full_line" | awk -F'#' '{print $1}' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') desc=$(echo "$full_line" | awk -F'#' '{print $2}' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') command_part=$(echo "$full_line" | awk -F'#' '{print $3}' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') # 预览窗口的显示逻辑 echo "--- 名称 ---" echo "$name" echo "" echo "--- 说明 ---" echo "$desc" echo "" echo "--- 命令 ---" if [ -f "$command_part" ]; then echo "$command_part" echo "" echo "--- 文件内容 ---" cat "$command_part" 2>/dev/null || echo "无法读取文件内容" else echo "$command_part" fi else echo "未找到对应的命令" fi EOF chmod +x "$preview_script" # --- 模糊搜索 --- local selected_line selected_line=$(grep -v "^#" "$command_file" | # 使用#作为分隔符,让fzf只搜索第一部分(名称) awk -F'#' '{print $1}' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | fzf --height=40% --tac \ --query="$initial_query" \ --header "↑↓ 选择, Enter 执行, Esc 退出 (或 cmd <快捷词> 直接调用)" \ --preview "$preview_script '$command_file' {}") # 清理临时文件 rm -f "$preview_script" # 如果用户选择了,获取名称部分 if [ -n "$selected_line" ]; then selected_line=$(echo "$selected_line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') fi if [ -z "$selected_line" ]; then echo "已取消。" return 0 fi # 从原文件中重新获取完整命令 local full_line full_line=$(grep -v "^#" "$command_file" | awk -F'#' -v name="$selected_line" '{ first_field = $1 gsub(/^[[:space:]]+|[[:space:]]+$/, "", first_field) if (first_field == name) print $0 }' | head -1) # 提取三部分 local name_part desc_part command_to_run name_part=$(echo "$full_line" | awk -F'#' '{print $1}' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') desc_part=$(echo "$full_line" | awk -F'#' '{print $2}' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') command_to_run=$(echo "$full_line" | awk -F'#' '{print $3}' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') echo "▶ $name_part【$desc_part】" # 执行逻辑 - 对sh文件使用source执行 if [ -f "$command_to_run" ]; then if [[ "$command_to_run" == *.sh ]]; then source "$command_to_run" elif [ -x "$command_to_run" ]; then "$command_to_run" else source "$command_to_run" fi else eval "$command_to_run" fi } cmd() { local command_file="/Users/linbin/SynologyDrive/附件/590/cmd/my_commands" # 检查命令文件是否存在 if [ ! -f "$command_file" ]; then echo "命令文件 $command_file 不存在。" return 1 fi # --- 处理直接调用(支持模糊匹配)--- # 检查是否提供了参数 (如: cmd lsa) if [ "$#" -gt 0 ]; then # 将所有参数用空格连接起来构造精确匹配模式 local shortcut="" for arg in "$@"; do if [ -n "$shortcut" ]; then shortcut="$shortcut $arg" else shortcut="$arg" fi done # 统一使用模糊匹配逻辑处理所有输入 # 将所有参数用空格连接起来进行模糊匹配 local all_args="" for arg in "$@"; do if [ -n "$all_args" ]; then all_args="$all_args $arg" else all_args="$arg" fi done fuzzy_matches=$(grep -v "^#" "$command_file" | awk -v keywords="$all_args" -F'#' ' { # 提取第一部分(名称)并trim空格 name_part = $1 gsub(/^[[:space:]]+|[[:space:]]+$/, "", name_part) # 将关键字按空格分割并检查每个关键字是否都匹配 n = split(keywords, kw_array, " ") match_all = 1 for (i = 1; i <= n; i++) { # 检查关键字是否为空,并且是否在name_part中存在 if (kw_array[i] != "" && index(name_part, kw_array[i]) == 0) { match_all = 0 break } } if (match_all == 1) print $0 }') if [ -n "$fuzzy_matches" ]; then # 统计匹配数量 - 只统计非空行 local match_count match_count=$(echo "$fuzzy_matches" | grep -c '.') if [ "$match_count" -eq 1 ]; then # 只有一个模糊匹配,直接执行 local name_part desc_part command_to_run name_part=$(echo "$fuzzy_matches" | awk -F'#' '{print $1}' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') desc_part=$(echo "$fuzzy_matches" | awk -F'#' '{print $2}' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') command_to_run=$(echo "$fuzzy_matches" | awk -F'#' '{print $3}' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') echo "▶ $name_part【$desc_part】" # 执行命令 - 对sh文件使用source执行 if [ -f "$command_to_run" ]; then if [[ "$command_to_run" == *.sh ]]; then source "$command_to_run" elif [ -x "$command_to_run" ]; then "$command_to_run" else source "$command_to_run" fi else eval "$command_to_run" fi return 0 else # 多个匹配,进入交互模式让用户选择 echo "找到 $match_count 个匹配项:" echo "$fuzzy_matches" | awk -F'#' '{print $1}' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | nl -b a echo "" # 直接进入交互模式 interactive_mode "" "$all_args" return 0 fi else echo "未找到匹配项,进入交互搜索模式..." # 进入交互模式 interactive_mode "" "$all_args" fi # 如果没有提供参数,直接进入交互模式 else interactive_mode fi }