本文目录导读:

我来介绍几种在Shell脚本中实现环形缓冲区的方法:
方法1:使用数组实现(Bash 4.0+)
#!/bin/bash
# 环形缓冲区实现
declare -a buffer=()
buffer_size=5
head=0
tail=0
count=0
# 初始化缓冲区
init_buffer() {
buffer=()
for ((i=0; i<buffer_size; i++)); do
buffer[$i]=""
done
head=0
tail=0
count=0
}
# 写入数据
write_buffer() {
local data="$1"
if [ $count -eq $buffer_size ]; then
echo "Buffer full, overwriting oldest data"
head=$(( (head + 1) % buffer_size ))
else
count=$((count + 1))
fi
buffer[$tail]="$data"
tail=$(( (tail + 1) % buffer_size ))
}
# 读取数据
read_buffer() {
if [ $count -eq 0 ]; then
echo "Buffer empty"
return 1
fi
local data="${buffer[$head]}"
buffer[$head]=""
head=$(( (head + 1) % buffer_size ))
count=$((count - 1))
echo "$data"
}
# 查看缓冲区内容
show_buffer() {
echo "Buffer contents:"
local idx=$head
for ((i=0; i<count; i++)); do
echo "[$(( (idx + i) % buffer_size ))]: ${buffer[$(( (idx + i) % buffer_size ))]}"
done
}
# 测试
init_buffer
# 写入测试数据
for i in {1..7}; do
write_buffer "Data_$i"
echo "Wrote: Data_$i"
done
show_buffer
echo -e "\nReading data:"
while read_buffer 2>/dev/null; do
:
done
方法2:使用文件实现(更通用)
#!/bin/bash
# 基于文件的环形缓冲区
BUFFER_DIR="/tmp/ring_buffer_$$"
BUFFER_SIZE=5
counter=0
# 初始化缓冲区
init_file_buffer() {
mkdir -p "$BUFFER_DIR"
echo 0 > "$BUFFER_DIR/head"
echo 0 > "$BUFFER_DIR/tail"
echo 0 > "$BUFFER_DIR/count"
for ((i=0; i<BUFFER_SIZE; i++)); do
: > "$BUFFER_DIR/$i"
done
}
# 写入数据
write_file_buffer() {
local data="$1"
local count=$(cat "$BUFFER_DIR/count")
local tail=$(cat "$BUFFER_DIR/tail")
if [ "$count" -eq "$BUFFER_SIZE" ]; then
local head=$(cat "$BUFFER_DIR/head")
head=$(( (head + 1) % BUFFER_SIZE ))
echo "$head" > "$BUFFER_DIR/head"
else
count=$((count + 1))
echo "$count" > "$BUFFER_DIR/count"
fi
echo "$data" > "$BUFFER_DIR/$tail"
tail=$(( (tail + 1) % BUFFER_SIZE ))
echo "$tail" > "$BUFFER_DIR/tail"
}
# 读取数据
read_file_buffer() {
local count=$(cat "$BUFFER_DIR/count")
if [ "$count" -eq 0 ]; then
echo "Buffer empty"
return 1
fi
local head=$(cat "$BUFFER_DIR/head")
local data=$(cat "$BUFFER_DIR/$head")
: > "$BUFFER_DIR/$head"
head=$(( (head + 1) % BUFFER_SIZE ))
echo "$head" > "$BUFFER_DIR/head"
count=$((count - 1))
echo "$count" > "$BUFFER_DIR/count"
echo "$data"
}
# 清理
cleanup_file_buffer() {
rm -rf "$BUFFER_DIR"
}
# 测试
init_file_buffer
# 写入测试数据
for i in {1..7}; do
write_file_buffer "File_Data_$i"
echo "Wrote: File_Data_$i"
done
echo -e "\nReading file buffer:"
while read_file_buffer 2>/dev/null; do
:
done
cleanup_file_buffer
方法3:使用命名管道实现(FIFO)
#!/bin/bash
# 使用命名管道实现环形缓冲区
PIPE_NAME="/tmp/ring_pipe"
BUFFER_SIZE=5
# 创建命名管道
init_pipe_buffer() {
if [ ! -p "$PIPE_NAME" ]; then
mkfifo "$PIPE_NAME"
fi
# 后台进程管理缓冲区
(
declare -a buffer=()
local head=0
local tail=0
local count=0
while true; do
if read line; then
# 解析指令
case "$line" in
WRITE:*)
data="${line#WRITE:}"
if [ $count -eq $BUFFER_SIZE ]; then
head=$(( (head + 1) % BUFFER_SIZE ))
else
count=$((count + 1))
fi
buffer[$tail]="$data"
tail=$(( (tail + 1) % BUFFER_SIZE ))
echo "OK" >&3
;;
READ)
if [ $count -gt 0 ]; then
data="${buffer[$head]}"
head=$(( (head + 1) % BUFFER_SIZE ))
count=$((count - 1))
echo "$data" >&3
else
echo "EMPTY" >&3
fi
;;
SHOW)
echo "Buffer[${#buffer[@]}] count=$count" >&3
;;
QUIT)
break
;;
esac
fi
done
) < "$PIPE_NAME" 3>&1 &
BUFFER_PID=$!
}
# 写入数据
write_pipe_buffer() {
echo "WRITE:$1" > "$PIPE_NAME"
read response < "$PIPE_NAME"
echo "Write response: $response"
}
# 读取数据
read_pipe_buffer() {
echo "READ" > "$PIPE_NAME"
read data < "$PIPE_NAME"
echo "$data"
}
# 测试
init_pipe_buffer
sleep 0.1 # 等待后台进程启动
# 写入测试数据
for i in {1..7}; do
write_pipe_buffer "Pipe_Data_$i"
done
echo -e "\nReading pipe buffer:"
for ((i=0; i<5; i++)); do
read_pipe_buffer
done
# 清理
echo "QUIT" > "$PIPE_NAME"
kill $BUFFER_PID 2>/dev/null
rm -f "$PIPE_NAME"
方法4:简单Shell数组实现(最实用)
#!/bin/bash
# 简单实用的环形缓冲区
ring_buffer() {
local -n arr=$1
local -n idx=$2
local size=$3
# 添加元素
if [ "$4" = "push" ]; then
arr[$idx]=$5
idx=$(( (idx + 1) % size ))
# 获取所有元素
elif [ "$4" = "get_all" ]; then
for ((i=0; i<${#arr[@]}; i++)); do
if [ -n "${arr[$i]}" ]; then
echo "${arr[$i]}"
fi
done
# 获取最新元素
elif [ "$4" = "get_latest" ]; then
local last=$(( (idx - 1 + size) % size ))
echo "${arr[$last]}"
fi
}
# 使用示例
declare -a buffer=()
current=0
buffer_size=5
# 写入数据
for i in {1..10}; do
ring_buffer buffer current $buffer_size "push" "Log_Entry_$i"
done
echo "Current buffer contents:"
ring_buffer buffer current $buffer_size "get_all"
使用建议
- 数组实现:最简单,适合小型应用
- 文件实现:可持久化,适合进程间通信
- 命名管道:适合实时数据流处理
- 关联数组:可以扩展为更复杂的缓存结构
选择哪种方法取决于你的具体需求:数据量大小、是否需要持久化、是否需要进程间通信等。