Fortune - 适配改造分享
fortune 缺陷描述
- 默认词库不合心意,但可手动维护
- 纯随机算法,无法保证每条摘录能出现
- 默认输出文本颜色样式呆板
设计思路
- lolcat , cowsay 解决 呆板, 实现彩虹色 输出
- fortune 参数可指定 词库,但无记忆统计功能
- 哈希桶 思路解决 记忆
- 编写Makefile实现自动编译并生成哈希文件
- 编写Function 适配
- 词库直接由坚果云同步,解决备份不丢失问题
最初我只描述 实现效果,没有参与逻辑设计,被动测试和把控;
随机生成的思路 一眼假 或者说是 似是而非,总是有漏洞,所以 AI还需要发展,需要设计者 参与核心思路的设计 和 主动把控;
AI作为 解放代码和快速编写还是 很不错的,快速生成,简单审核内容和逻辑是否偏离
使用哈希 一次性 将 所有内容 哈希化,不依赖原生fortune直接调用,因为它是纯随机的,通过哈希可以主动校验
微调lolcat 避免彩虹干扰眼睛
微调 cowsay对中文,过长文本的排版错乱限制,手动动态生成 边框
统计打印输出剩余可读数量
初次AI使用 rm命令,我系统 rm已被safely-rm接管,除非手动指出绝对路径,但 本身的思路就是不对,只需要将文件内容清空而非 删除再重建
安装
基础包
仅安装这一个 其余通过脚本来满足个性化现代改造
brew install fortune #提供基础fortune设置词库和解析词库的能力验证:是否安装成功
❯ brew info fortune ─╯
==> fortune ✔: stable 9708 (bottled)
Infamous electronic fortune-cookie generator
https://www.ibiblio.org/pub/linux/games/amusements/fortune/!INDEX.html
Installed (on request)
From: https://mirrors.ustc.edu.cn/homebrew-core.git/Formula/f/fortune.rb
License: BSD-4-Clause-UC
==> Installed Kegs and Versions
fortune ✔ 9708 (85 files, 2.6MB) [Linked]创建个人词库
创建 词库根文件夹,示例提供的是00Fortunes 下方 提供 目录结构 bin 存储编译结果, Makefile为编译工具, src存放词库 因为 src 文件 走坚果云同步所以是引用文件夹,也一并补充 具体内容
❯ tree ─╯
.
├── bin
│ ├── cli_tools
│ ├── cli_tools.dat
│ ├── micro_think
│ └── micro_think.dat
├── Makefile
└── src -> $HOME/Library/CloudStorage/坚果云/src
❯ tree
.
├── cli_tools
└── micro_think
创建函数脚本
建议创建独立的zsh脚本文件,引入到你的配置文件中 或者直接复制粘贴到你的配置文件(.zshrc/.bashrc)中
默认函数名称 cs 和 fortune-sync 可修改
# 2026年06月06日
# 打印输出函数
# fortune_cs.zsh文件形式保存
function cs() {
local fortune_dir="$HOME/00Fortunes/bin"
local pool_file="$fortune_dir/.fortune_hash_pool"
local map_file="$fortune_dir/.fortune_hash_map"
local temp_output="$fortune_dir/.fortune_current"
# =================================================================
# ✨ 严选护眼相位池
# =================================================================
local eye_safe_phases=(30 45 60 15 135 150 165 315 330)
local random_idx=$(( (RANDOM % ${#eye_safe_phases[@]}) + 1 ))
local chosen_phase=${eye_safe_phases[$random_idx]}
local md5_cmd="md5"
! command -v md5 &>/dev/null && md5_cmd="md5sum"
# =================================================================
# 逻辑 1:桶初始化
# =================================================================
if [[ ! -f "$pool_file" || ! -s "$pool_file" || ! -f "$map_file" || ! -s "$map_file" ]]; then
echo "🔄 [哈希重置]: 正在为你的精美词库建立全量唯一哈希索引池..."
: > "$map_file"
: > "$pool_file"
local raw_all=""
for f in "$fortune_dir"/*; do
if [[ -f "$f" && "${f:t}" != *.dat && "${f:t}" != .* && "${f:t}" != *.tmp && "${f:t}" != *.pool && "${f:t}" != *.map ]]; then
raw_all+="$(cat "$f" | tr -d '\r')\n%\n"
fi
done
echo "$raw_all" | awk '
BEGIN { RS="\n%\n"; block="" }
{
clean_block = $0;
gsub(/^[ \t\n]+|[ \t\n]+$/, "", clean_block);
if (clean_block != "" && clean_block != "%") {
print "---BLOCK_START---"
print $0
print "---BLOCK_END---"
}
}
' | while IFS= read -r line; do
if [[ "$line" == "---BLOCK_START---" ]]; then
block_content=""
elif [[ "$line" == "---BLOCK_END---" ]]; then
local my_hash=$(echo -n "$block_content" | $md5_cmd | awk '{print $1}')
echo "==HASH:${my_hash}==" >> "$map_file"
echo "$block_content" >> "$map_file"
echo "%%" >> "$map_file"
echo "$my_hash" >> "${pool_file}.raw"
else
[[ -z "$block_content" ]] && block_content="$line" || block_content+=$'\n'"$line"
fi
done
if [[ -f "${pool_file}.raw" ]]; then
shuf "${pool_file}.raw" > "$pool_file"
: > "${pool_file}.raw"
fi
fi
# =================================================================
# 逻辑 2:精准消费
# =================================================================
local target_hash=$(head -n 1 "$pool_file" | tr -d ' \t\r\n')
if [[ -n "$target_hash" && -f "$map_file" ]]; then
: > "$temp_output"
sed -n "/==HASH:${target_hash}==/,/^%%/p" "$map_file" | sed "1d;/\^%%/d" | sed '/^%%/d' > "$temp_output"
if [[ -s "$temp_output" ]]; then
# =========================================================
# ✨ 【全新护眼抗洪核心】:折行防爆 + 动态方框
# =========================================================
(
# 1. 展开 Tab 键,同时利用 fold 命令限制单行视觉最大显示宽为 90(支持中文智能截断)
# 这样超长命令会自动换到下一行,绝不会把方框和 lolcat 撑爆!
local clean_text=$(expand -t 4 "$temp_output" | fold -s -w 90)
# 2. 动态精准计算截断后的最大列宽
local max_w=0
while IFS= read -r line; do
local line_w=${(m)#line}
(( line_w > max_w )) && max_w=$line_w
done <<< "$clean_text"
local padding_x=4
(( max_w < 24 )) && max_w=24
echo ""
# 绘制方框顶部
printf " ╭"
printf '─%.0s' {1..$((max_w + padding_x * 2))}
printf "╮\n"
printf " │"
printf ' %.0s' {1..$((max_w + padding_x * 2))}
printf "│\n"
# 3. 完美包裹折行后的正文
while IFS= read -r line; do
local line_w=${(m)#line}
local total_spaces=$((max_w - line_w))
printf " │"
printf ' %.0s' {1..$padding_x}
printf "%s" "$line"
printf ' %.0s' {1..$((total_spaces + padding_x))}
printf "│\n"
done <<< "$clean_text"
printf " │"
printf ' %.0s' {1..$((max_w + padding_x * 2))}
printf "│\n"
# 绘制方框底部
printf " ╰"
printf '─%.0s' {1..$((max_w + padding_x * 2))}
printf "╯\n"
) | lolcat -p $chosen_phase -F 0.20 -S 1
# 4. 灰色小牛独立打印
echo -e "\033[1;30m \\ ^__^"
echo " \\ (oo)\\_______"
echo " (__)\\ )\\/\\"
echo " ||----w |"
echo " || ||\033[0m"
echo ""
# =========================================================
# 5. 裁剪哈希桶
# =========================================================
local tmp_pool="${pool_file}.tmp"
tail -n +2 "$pool_file" > "$tmp_pool"
cat "$tmp_pool" > "$pool_file"
: > "$tmp_pool"
# 6. 统计剩余数量
local remain_count=$(wc -l < "$pool_file" | tr -d ' ')
echo -e "\033[0;37m📊 [词库统计]: 今日箴言已读。池子里还剩 💡 \033[1;32m$remain_count\033[0;37m 条未读内容。\033[0m"
else
fortune "$fortune_dir" | lolcat
fi
else
echo "🚨 [异常触发]: 索引映射发生错位,正在强制重置重洗..."
: > "$pool_file"
fortune "$fortune_dir" | lolcat
fi
[[ -f "$temp_output" ]] && : > "$temp_output"
}
# 2026年06月06日
# 功能清单:
# 1. 编译生成 bat源词库
# 2. 清理既往中间池, 保证 源词库 与 中间池一致的问题
# Makefile 文件
# 2026年06月06日
# 功能清单:
# 1. 编译生成 fortune 专用 .dat 源词库
# 2. 生成最新哈希文件
# 路径定义
SRC_DIR = src
BIN_DIR = bin
STRFILE = /opt/homebrew/bin/strfile
# 【核心升级】定义最新的哈希池与哈希映射表文件路径
HASH_POOL = $(BIN_DIR)/.fortune_hash_pool
HASH_MAP = $(BIN_DIR)/.fortune_hash_map
# 获取 src 下所有没有后缀的文件名
SOURCES = $(wildcard $(SRC_DIR)/*)
# 定义目标文件:每个源文件在 bin 目录下都要有一个对应的文本和 .dat 文件
TARGET_TEXTS = $(patsubst $(SRC_DIR)/%, $(BIN_DIR)/%, $(SOURCES))
TARGET_DATS = $(patsubst $(SRC_DIR)/%, $(BIN_DIR)/%.dat, $(SOURCES))
all: $(BIN_DIR) $(TARGET_DATS)
# 创建 bin 目录
$(BIN_DIR):
mkdir -p $(BIN_DIR)
# 规则:当 src 下的文本更新时,同步到 bin 并生成 .dat
$(BIN_DIR)/%.dat: $(SRC_DIR)/%
@echo "🛠️ Processing: $<"
@cp $< $(BIN_DIR)/$*
@$(STRFILE) -s $(BIN_DIR)/$* $(BIN_DIR)/$*.dat
# 【数据一致性联动】只要有任何源文件更新,使用原生系统命令绝对路径强刷哈希桶与字典
# 绕过 rm-safely 的物理删除,迫使 cs 函数在下次运行时重新全量生成哈希字典并打散洗牌
@/bin/rm -f $(HASH_POOL) $(HASH_MAP)
clean:
rm -rf $(BIN_DIR)
.PHONY: all clean
# fortune-sync.zsh独立文件形式保存
fortune-sync () {
(
cd "$HOME/00Fortunes" && make
)
}使用
词库维护 fortun-sync
前置安装 工作完成,并重启刷新配置文件; 样例词库 cli_tools;
每条以%作为分隔符
编辑完成后fortune-sync生成词库文件
rm-safely更安全
rm --help #查看帮助
rmbuild * # 清空build编译输出目录
rm --list-trash # 列出
rm --empty-trash #清空
/bin/rm -f #系统内置rm命令地址
%
ccache -z #重置统计
ccache -s #查看统计
%
container start -i gcc16 # 交互模式进入容器
%
brewup #批量更新工具链
%
mo optimize # 硬件优化
%
j music #跳转已进入的目录
autojump 底层是这个,后续有更复杂需求 ,编写函数
%
fortune --- 个人谮言 /备忘录 /Users/songhoujin/00Fortunes/src
fortune-sync #编辑更新完 同步更新生成最新哈希值
cs 基于哈希桶的带有记忆功能的fortune函数
%
Little Snitch - 网络出关设置;
%
Object-See
BlockBlock - 检测持久化拦截
KnockKnock - 恶意软件检测
%
p10k configure # 自带的配置流程
%
cloc - 静态代码信息打印输出
%打印输出 cs
直接 输入cs 即可查看效果

知识蒸馏整理
通过 编写自定义脚本,和AI交互中,学到哪些新的知识和技能?
查看 man 帮助手册操作
默认使用
less文本阅读器 所以man 命令的快捷键 和 less 一致; 基础翻页
f(Forward) 向下翻一页; Sace, PageDown
b (Backward) 向上翻一页; PageUp
d (Down) 向下翻半页;
u (Up) 向上翻半页; 微调滚行
j :向下滚动一行
k :向上滚动一行 瞬间跃迁
g: 手册顶部
G:手册底部强力搜索
/+关键字 ,向下搜索内容, eg: /---stream ,高亮所有匹配项
?+关键字, 向上搜索内容
n(Next):配合搜索使用, 跳转到下一个高亮关键字
N(Shift+n) 配合搜索使用, 反向跳转上一个高亮关键字退出 q(QUit) 退出手册,切回控制台
bat,cat获取文件内容pbcopy将管道内容粘贴到剪切板中tree打印输出目录结构cloc代码行统计工具