将.bash_history按命令分类到独立文件的脚本优化问题
优化bash历史记录分类与清理脚本
问题根源
你之前的写法grep -E -v "^(${categories[@]})"失效,是因为数组直接展开后会被shell按空格拆分,导致正则表达式格式错误(比如数组含带空格的命令时,会被拆成多个无效模式)。
优化方案
通过统一构建转义后的正则表达式,复用categories数组完成提取和清理操作,彻底避免规则重复定义的问题。
完整脚本
#!/bin/bash # 定义需要分类的命令列表(支持带空格的命令) categories=("git" "docker" "docker-compose" "kubectl") # 历史文件路径,优先用环境变量,否则默认~/.bash_history BASH_HISTORY="${BASH_HISTORY:-$HOME/.bash_history}" # 构建正则表达式:转义每个命令的特殊字符,用|连接成有效分组 regex=$(printf "%q|" "${categories[@]}" | sed 's/|$//') # 1. 提取匹配记录到对应分类文件 for cmd in "${categories[@]}"; do # 匹配以当前命令开头的行(\b确保不会误匹配类似gitlab-runner这类命令) grep -E "^$cmd\b" "$BASH_HISTORY" >> "$HOME/.bash_history.$cmd" done # 2. 从原历史文件移除已分类的记录 # 用临时文件替换原文件,避免直接修改导致的文件损坏 grep -E -v "^($regex)\b" "$BASH_HISTORY" > "$BASH_HISTORY.tmp" && mv "$BASH_HISTORY.tmp" "$BASH_HISTORY" # 可选:刷新当前shell的历史记录,让修改立即生效 history -r
关键细节说明
- 正则构建:
printf "%q"会自动转义命令中的特殊字符(空格、括号等),确保正则匹配准确;sed 's/|$//'去掉最后多余的分隔符,形成git|docker|docker-compose|kubectl这类有效分组。 - 边界匹配:
\b是单词边界,避免误匹配前缀相似的命令(比如git不会匹配gitlab)。 - 安全修改:用临时文件替换原历史文件,防止IO异常导致原文件损坏。
扩展调整
如果需要匹配包含命令而非仅开头的记录,只需把提取规则的^$cmd\b改成\b$cmd\b,清理规则的^($regex)\b改成\b($regex)\b即可。
内容的提问来源于stack exchange,提问作者Paul_Capo
相关产品推荐
相关产品推荐

