Skip to Main Content
Fortune - 适配改造分享Back to Top

Fortune - 适配改造分享

4 minutes

fortune 缺陷描述

  1. 默认词库不合心意,但可手动维护
  2. 纯随机算法,无法保证每条摘录能出现
  3. 默认输出文本颜色样式呆板

设计思路

  1. lolcat , cowsay 解决 呆板, 实现彩虹色 输出
  2. fortune 参数可指定 词库,但无记忆统计功能
  3. 哈希桶 思路解决 记忆
  4. 编写Makefile实现自动编译并生成哈希文件
  5. 编写Function 适配
  6. 词库直接由坚果云同步,解决备份不丢失问题

最初我只描述 实现效果,没有参与逻辑设计,被动测试和把控;
随机生成的思路 一眼假 或者说是 似是而非,总是有漏洞,所以 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) 退出手册,切回控制台