2014-10-29 4 views
2

Я пытаюсь создать эффективный скрипт для чтения (большого) блока файлов для каждого блока и сохранить первую строку последнего блока чтения в файле. В моем случае это очень полезно, если я хочу передать файл в программу. Я могу остановить его и запустить его позже в той же строке, на которой он был остановлен раньше (что означает ту же строку блока).Чтение файла, блока за блок

Вот сценарий:

LINE_FILE=line-file 
READ_FILE=the_file 
BLOCK=1000 
LN_SUP=$(cat $LINE_FILE) 

#### 

trap "save_line ; exit" SIGHUP SIGINT SIGTERM SIGKILL 

save_line() 
{ 
    echo $LN_SUP > $LINE_FILE 
} 

block_cat() 
{ 
    TEXT=$(tail -n+$LN_SUP $READ_FILE | head -n $BLOCK) 
    echo "$TEXT" 
    if [ -n "$TEXT" ]; then 
     return 0 
    else 
     return -1 
    fi 
} 

test() 
{ 
    return 1 
} 

file_cat() 
{ 
    >&2 echo "First line to read the file : $LN_SUP" 
    block_cat $READ_FILE 
    while [ $? -eq 0 ]; do 
     LN_SUP=$(($LN_SUP + $BLOCK)) #Remember the new first line of the block 
     block_cat $READ_FILE 
    done 
} 

Это на самом деле работает, но не так быстро, как я ожидал.

Используется для вывода выходного сигнала на воздушный фильтр, и я теряю почти 18% эффективности.

Как вы думаете, есть ли лучший способ сделать это?

+0

Не открывать файл и многократно искать через него, вероятно, поможет. К сожалению, делать это в bash не совсем возможно, если вы не хотите читать последовательно с самого начала. –

ответ

0

Может быть, это будет делать:

#!/bin/bash 

line_file=line-file 
quantum=1000 
file=the_file 

die() { 
    (($#)) && printf '%s\n' "[email protected]" 
    exit 1 
} 

[[ -e $line_file ]] || echo "0" > "$line_file" 
[[ -f $line_file ]] || die "File \`$line_file' not found" 
[[ -r $line_file ]] || die "Can't read file \`$line_file'" 

read current_line < "$line_file" 

[[ $current_line = *([[:digit:]]) ]] || die "Error in file \`$line_file'" 
((current_line=10#$current_line)) 

callback() { 
    printf '%s\n' "${mary[@]}" 
    mary=() 
    echo "$1" > "$line_file" 
} 

mapfile -O "$current_line" -s "$current_line" -t -c "$quantum" -C callback mary < "$file" && callback 

Он использует mapfile и его редко (и не очень хорошо известен) обратный вызов и квантовый материал. Не удивляйтесь, если в первом блоке всего 999 строк. Остальные - 1000 строк. Для этого есть обходные пути, но я не думаю, что это очень важно в вашем случае.

Я действительно не пробовал, дайте мне знать, есть ли какие-либо недостатки.

Здесь есть много ненужных строк относительно вашего первоначального вопроса. Но eh, это просто обработка ошибок и рутинная проверка, которые не могут повредить. Вы можете сосредоточиться только на этом:

callback() { 
    printf '%s\n' "${mary[@]}" 
    mary=() 
    echo "$1" > "$line_file" 
} 

mapfile -O "$current_line" -s "$current_line" -t -c "$quantum" -C callback mary < "$file" && callback 

Таким образом, каждый раз quantum (здесь 1000) строки считываются, функция вызывается, с первым набором параметров для индекса массива, который будет установлен после обратного вызова. В этом обратном вызове мы просто выгружаем содержимое массива, очищаем этот массив и сохраняем позицию файла в line_file. Это так просто. Чтобы получить окончание файла, мы в последний раз позвоним callback.

Когда mapfile выполняется, -s "$current_line" говорит mapfile, чтобы пропустить много строк, и -O "$current_line" говорит mapfile начать назначая на этот индекс.

+0

Это работает как шарм! mapfile просто отлично работает. Обратите внимание, что я адаптировал квант к более высокому значению (10000). – thefiercerabbit

Смежные вопросы