Shell脚本如何实现环形缓冲区

wen 实用脚本 4

本文目录导读:

Shell脚本如何实现环形缓冲区

  1. 方法1:使用数组实现(Bash 4.0+)
  2. 方法2:使用文件实现(更通用)
  3. 方法3:使用命名管道实现(FIFO)
  4. 方法4:简单Shell数组实现(最实用)
  5. 使用建议

我来介绍几种在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"

使用建议

  1. 数组实现:最简单,适合小型应用
  2. 文件实现:可持久化,适合进程间通信
  3. 命名管道:适合实时数据流处理
  4. 关联数组:可以扩展为更复杂的缓存结构

选择哪种方法取决于你的具体需求:数据量大小、是否需要持久化、是否需要进程间通信等。

抱歉,评论功能暂时关闭!