204 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
| #!/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
 | ||
| } |