Чи можливо в баші почати читати файл із зміщення підрахунку байтів довільного обміну?


22

Я хочу знайти дату, яка знаходиться десь у журналі 8 Гб (текст).

Чи можу я трохи обійти повне послідовне читання і спочатку зробити двійкові розщеплення файлу (розмір) або якимось чином переміститися по файловій системі inodes(про яку я дуже мало знаю ), щоб почати читання з кожного розділеного пункту, поки не знайду відповідного зміщення від з чого почати пошук тексту для рядка, що містить дату?

tailЧитання останнього рядка не використовує звичайне послідовне зчитування, тому мені цікаво, чи цей інструмент якимось чином доступний у bash, чи мені потрібно використовувати Python чи C / C ++ ... але мене конкретно цікавить bashваріант ..


Відповіді:


8
for (( block = 0; block < 16; block += 1 ))
do 
    echo $block; 
    dd if=INPUTFILE skip=$((block*512))MB bs=64 count=1 status=noxfer 2> /dev/null | \
        head -n 1
done

який .. не створює файлів із розділеним тимчасовим режимом, пропускає блоки * 512 Мб даних при кожному запуску, зчитує 64 байти з цього положення та обмежує вихід на перший рядок із цих 64 байтів.

ви можете налаштувати 64 на все, що ви вважаєте, що вам потрібно.


@akira .. Це виглядає дуже добре, але я хочу переглянути це трохи більше спочатку .. (так, до завтра .....
Peter.O

1
@akira .. 'dd' є дивним. Він добре працює з двійковим роздвоєним пошуком ... Тепер я можу витягнути рядок regex'd (за його датою) з відсортованого файлу 8G протягом менше 1 секунди ... Отже, схоже, я досягну своїх 3 друга особиста ціль для вилучення діапазону дат між двома клавішами (включно) .. без урахування часу виводу, який змінюється залежно від того, скільки виводиться .. Я також буду використовувати ddдля цього ... Це чудовий інструмент! :)
Пітер.О

30

Це звучить так, як хочеться:

tail -c +1048576

або будь-яку кількість байтів, які ви хочете пропустити. Знак "плюс" повідомляє хвіст вимірювати з початку файлу замість кінця. Якщо ви використовуєте версію хвоста GNU, ви можете записати це як:

tail -c +1M

Щоб отримати фіксовану кількість байтів після вирізання, замість всього решти файлу просто переведіть його через голову:

tail -c +1048576 | head -c 1024

Гнучкість Linux / bash - дивовижна (я, безумовно, витратив занадто багато часу на перехід на Linux). Я щойно прийняв відповідь Акіри, але я це дотягнув, поки не оціню це більш повно. ddстрибає на певний байт (як це робиться tail), але це больове кодування навколо невідомої довжини рядка, а потім дзвінок до sed, щоб зняти провідні часткові лінії ... Схоже, хвостик | голова може зробити це безболісно (як швидко?) . Я не розумію, як голова може вимкнути кран на хвіст, але здається :) Це повинно бути так: Якщо голова перестає приймати, хвіст перестає надсилати (і зупиняє подальше читання). Треба піти .. завтра.
Пітер.О

@ fred.bear: tail/ headтакож не можуть сліпо вгадати довжини рядків. вам доведеться перейти до позиції x, і тоді ви можете шукати ліворуч або праворуч від x для наступного \n. не має значення, як називається програма. Таким чином, в обох випадках ви переходите до x, а потім headшукаєте праворуч на наступний кінець рядка.
акіра

tail|headдає можливість не турбуватися взагалі про ddпорахуємо = значення. Якщо "dd", якщо я не захоплю достатньо даних, це "гра закінчена". Гнучкість довільних довжин ліній велика. Я написав функцію для 'dd', яка повертає «наступний найближчий» повний рядок та його зміщення, але я вважаю за краще уникати проблеми із довжиною. Зараз я перевірив хвостик | голову, і вона спочатку добре працює (для компенсації = 100 МБ), але різко сповільнюється, щоб зайняти 2 хв на один доступ при зміщенні = 8 ГБ (я можу awkце за 1 хв) ... так що це чудово для менших файлів .. Дякую за те, що я в курсі хвоста / голови комбо :)
Peter.O

2

Я б спробував щось подібне, щоб розділити журнал на шматки 512MiB для швидшого розбору.

split <filename> -b 536870912

Якщо ви шукаєте файл, працює наступне:

for file in x* ; do
  echo $file
  head -n 1 $file
done

Використовуйте цей вихід, щоб визначити, який файл зібрати для вашої дати.


Дякую, але це повільніше, ніж послідовний пошук. Подивіться на мої коментарі тут unix.stackexchange.com/questions/8121/… (замість того, щоб переписувати тут те саме)
Peter.O

використовуючи "розділити", ви торкаєтесь кожного байта один раз. якщо ви це зробите, ви можете просто зірвати і цілі 8 Гбіт.
акіра

@sifusam .. Я хочу зробити бінарний пошук поділу ( а не тільки розділити файли) en.wikipedia.org/wiki/Binary_search_algorithm ... так що це був хороший відповідь на питання :) різний .. Спасибі за відповідь .. +1, щоб ви
закатали

0

Ось мій сценарій, я шукаю перший рядок, коли перше поле відповідає моєму номеру. Рядки сортуються відповідно до першого поля. Я використовую dd для перевірки першого рядка блоків 128K, потім переходжу до блоку та здійснюю пошук. Це підвищує ефективність файлу понад 1М.

Будь-який коментар чи виправлення вдячні!

#!/bin/bash

search=$1;
f=$2;

bs=128;

max=$( echo $(du $f | cut -f1)" / $bs" | bc );
block=$max;
for i in $(seq 0 $max); do
 n=$(dd bs=${bs}K skip=$i if=$f 2> /dev/null| head -2 | tail -1 | cut -f1)
 if [ $n -gt $search ]; then
  block=`expr $i - 1` 
  break;
 fi
done; 
dd bs=${bs}K skip=$block if=$f 2> /dev/null| tail -n +2 | awk -v search="$search" '$1==search{print;exit 1;};$1>search{exit 1;};';

* EDIT * ** Grep набагато швидше і вивів ще краще

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.