本文目录导读:

我来详细介绍Shell脚本实现LRU(Least Recently Used)缓存的方法。
基础实现 - 使用文件系统
简单文件版本
#!/bin/bash
# LRU缓存文件路径
CACHE_FILE="/tmp/lru_cache.txt"
CACHE_MAX_SIZE=5
# 初始化缓存文件
init_cache() {
if [ ! -f "$CACHE_FILE" ]; then
touch "$CACHE_FILE"
fi
}
# 获取缓存
cache_get() {
local key="$1"
local value
# 查找key是否存在
value=$(grep "^$key:" "$CACHE_FILE" 2>/dev/null | cut -d: -f2)
if [ -n "$value" ]; then
# 更新访问时间 - 将该项移到文件末尾
grep -v "^$key:" "$CACHE_FILE" > "${CACHE_FILE}.tmp"
echo "$key:$value" >> "${CACHE_FILE}.tmp"
mv "${CACHE_FILE}.tmp" "$CACHE_FILE"
echo "$value"
fi
}
# 设置缓存
cache_set() {
local key="$1"
local value="$2"
# 如果key已存在,先删除旧记录
if grep -q "^$key:" "$CACHE_FILE" 2>/dev/null; then
grep -v "^$key:" "$CACHE_FILE" > "${CACHE_FILE}.tmp"
mv "${CACHE_FILE}.tmp" "$CACHE_FILE"
fi
# 添加新记录
echo "$key:$value" >> "$CACHE_FILE"
# 检查并清理超出大小的项目
local lines=$(wc -l < "$CACHE_FILE")
if [ "$lines" -gt "$CACHE_MAX_SIZE" ]; then
# 删除最旧的项目(文件头部)
tail -n "$CACHE_MAX_SIZE" "$CACHE_FILE" > "${CACHE_FILE}.tmp"
mv "${CACHE_FILE}.tmp" "$CACHE_FILE"
fi
}
# 删除缓存项
cache_del() {
local key="$1"
grep -v "^$key:" "$CACHE_FILE" > "${CACHE_FILE}.tmp"
mv "${CACHE_FILE}.tmp" "$CACHE_FILE"
}
# 清空缓存
cache_clear() {
> "$CACHE_FILE"
}
# 查看缓存状态
cache_status() {
echo "=== LRU Cache Status ==="
echo "Max Size: $CACHE_MAX_SIZE"
echo "Current Size: $(wc -l < "$CACHE_FILE")"
echo "Contents (least recent first):"
cat "$CACHE_FILE" | while IFS=: read -r key value; do
echo " $key -> $value"
done
}
使用关联数组的内存版本
#!/bin/bash
# 内存LRU缓存实现(使用关联数组)
declare -A LRU_CACHE
declare -a LRU_ORDER=()
CACHE_MAX_SIZE=10
# 获取缓存值
lru_get() {
local key="$1"
if [[ -v LRU_CACHE["$key"] ]]; then
# 更新访问顺序
update_access_order "$key"
echo "${LRU_CACHE[$key]}"
return 0
fi
return 1
}
# 设置缓存值
lru_set() {
local key="$1"
local value="$2"
# 如果key已存在,更新值
if [[ -v LRU_CACHE["$key"] ]]; then
LRU_CACHE["$key"]="$value"
update_access_order "$key"
else
# 检查缓存是否已满
if [ ${#LRU_ORDER[@]} -ge "$CACHE_MAX_SIZE" ]; then
# 移除最久未使用的项
local oldest="${LRU_ORDER[0]}"
unset LRU_CACHE["$oldest"]
LRU_ORDER=("${LRU_ORDER[@]:1}")
fi
# 添加新项
LRU_CACHE["$key"]="$value"
LRU_ORDER+=("$key")
fi
}
# 更新访问顺序
update_access_order() {
local key="$1"
local index=-1
for i in "${!LRU_ORDER[@]}"; do
if [ "${LRU_ORDER[$i]}" == "$key" ]; then
index=$i
break
fi
done
if [ $index -ge 0 ]; then
# 移除当前位置
unset 'LRU_ORDER[$index]'
# 重新索引数组
LRU_ORDER=("${LRU_ORDER[@]}")
# 添加到末尾
LRU_ORDER+=("$key")
fi
}
# 删除缓存项
lru_del() {
local key="$1"
if [[ -v LRU_CACHE["$key"] ]]; then
unset LRU_CACHE["$key"]
# 从顺序数组中移除
for i in "${!LRU_ORDER[@]}"; do
if [ "${LRU_ORDER[$i]}" == "$key" ]; then
unset 'LRU_ORDER[$i]'
LRU_ORDER=("${LRU_ORDER[@]}")
break
fi
done
fi
}
# 显示缓存状态
lru_status() {
echo "=== Memory LRU Cache ==="
echo "Max Size: $CACHE_MAX_SIZE"
echo "Current Size: ${#LRU_CACHE[@]}"
echo "Access Order (oldest first):"
for key in "${LRU_ORDER[@]}"; do
echo " $key -> ${LRU_CACHE[$key]}"
done
}
使用临时文件的增强版本
#!/bin/bash
# LRU缓存类
LRUCache() {
# 构造函数
local -n self=$1
self[base_dir]="/tmp/lru_cache_$$"
self[max_size]=10
# 初始化
mkdir -p "${self[base_dir]}"
# 获取缓存
get() {
local key="$1"
local cache_file="${self[base_dir]}/${key}"
if [ -f "$cache_file" ]; then
# 更新时间戳
touch "$cache_file"
cat "$cache_file"
return 0
fi
return 1
}
# 设置缓存
set() {
local key="$1"
local value="$2"
local cache_file="${self[base_dir]}/${key}"
echo "$value" > "$cache_file"
# 检查并淘汰
evict_if_needed
}
# 淘汰最久未使用的
evict_if_needed() {
local count=$(ls -1t "${self[base_dir]}/" 2>/dev/null | wc -l)
if [ "$count" -gt "${self[max_size]}" ]; then
# 找到最久未访问的文件并删除
ls -1t "${self[base_dir]}/" | tail -n $((count - self[max_size])) |
while read file; do
rm -f "${self[base_dir]}/$file"
done
fi
}
# 获取统计信息
stats() {
echo "Cache directory: ${self[base_dir]}"
echo "Max size: ${self[max_size]}"
echo "Current size: $(ls -1 "${self[base_dir]}/" 2>/dev/null | wc -l)"
echo "Recent access order (most recent first):"
ls -1t "${self[base_dir]}/" 2>/dev/null | head -10
}
# 清理
cleanup() {
rm -rf "${self[base_dir]}"
}
}
# 使用示例
example_usage() {
# 创建缓存实例
declare -A my_cache
LRUCache my_cache
my_cache[max_size]=5
# 设置缓存
my_cache set "key1" "value1"
my_cache set "key2" "value2"
my_cache set "key3" "value3"
# 获取缓存
echo "key1 value: $(my_cache get 'key1')"
# 显示状态
my_cache stats
# 清理
my_cache cleanup
}
使用SQLite的持久化版本
#!/bin/bash
# SQLite LRU缓存实现
LRU_DB="/tmp/lru_cache.db"
# 初始化数据库
init_sqlite_cache() {
sqlite3 "$LRU_DB" "CREATE TABLE IF NOT EXISTS cache (
key TEXT PRIMARY KEY,
value TEXT,
access_time INTEGER
);"
}
# 获取缓存
sqlite_cache_get() {
local key="$1"
init_sqlite_cache
local result=$(sqlite3 "$LRU_DB" "SELECT value, access_time FROM cache WHERE key='$key'")
if [ -n "$result" ]; then
# 更新时间戳
sqlite3 "$LRU_DB" "UPDATE cache SET access_time=$(date +%s) WHERE key='$key'"
echo "$result" | cut -d'|' -f1
return 0
fi
return 1
}
# 设置缓存
sqlite_cache_set() {
local key="$1"
local value="$2"
local max_size=10
init_sqlite_cache
# 插入或更新
sqlite3 "$LRU_DB" "INSERT OR REPLACE INTO cache (key, value, access_time)
VALUES ('$key', '$value', $(date +%s))"
# 检查并淘汰
local count=$(sqlite3 "$LRU_DB" "SELECT COUNT(*) FROM cache")
if [ "$count" -gt "$max_size" ]; then
# 删除最久未使用的记录
sqlite3 "$LRU_DB" "DELETE FROM cache WHERE key IN (
SELECT key FROM cache ORDER BY access_time ASC LIMIT $((count - max_size))
)"
fi
}
完整测试脚本
#!/bin/bash
# 包含LRU实现
source ./lru_cache.sh
# 测试函数
test_lru_cache() {
echo "=== Testing LRU Cache ==="
# 使用内存版本
echo "Testing memory cache..."
lru_set "key1" "value1"
lru_set "key2" "value2"
lru_set "key3" "value3"
echo "Get key1: $(lru_get 'key1')"
echo "Get key2: $(lru_get 'key2')"
lru_status
# 测试淘汰
echo -e "\nAdding more items to trigger eviction..."
lru_set "key4" "value4"
lru_set "key5" "value5"
lru_set "key6" "value6"
lru_status
echo "Try to get evicted key (key3): $(lru_get 'key3' || echo 'NOT FOUND')"
}
# 执行测试
test_lru_cache
最佳实践建议
-
选择合适的实现方式:
- 小型缓存:使用关联数组
- 持久化需求:使用文件或SQLite
- 高性能需求:使用临时文件
-
并发安全:
- 使用文件锁处理并发访问
- 考虑使用
flock命令
-
性能优化:
- 使用哈希函数分散文件存储
- 实现二级缓存策略
- 定期清理过期项
-
错误处理:
- 检查文件操作是否成功
- 处理并发写入冲突
- 实现优雅的清理机制
这些实现可以根据你的具体需求进行调整和优化,选择哪种方式取决于你的使用场景、性能要求和数据持久化需求。