bash에서 임의의 바이트 수 오프셋에서 파일을 읽을 수 있습니까?


22

8GB 로그 (텍스트) 어딘가에 날짜를 찾고 싶습니다.

전체 순차 읽기를 무시하고 먼저 파일의 이진 분할 (크기)을 수행하거나 파일 시스템을 탐색하여 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

which .. 임시 분할 파일을 작성하지 않고 각 실행에서 * 512MB의 데이터 블록을 건너 뛰고 해당 위치에서 64 바이트를 읽고 출력을 해당 64 바이트의 첫 번째 행으로 제한합니다.

필요하다고 생각하는대로 64를 조정할 수 있습니다.


@akira .. 이것은 정말 좋아 보이지만 좀 더 먼저보고 싶습니다 .. (내일까지 .....
Peter.O

1
@akira .. 'dd'는 끔찍하다. 이진 분할 검색과 잘 작동합니다 ... 이제 1 초 안에 정렬 된 8G 파일에서 정규식 줄 (날짜 키로)을 추출 할 수 있습니다 ... 그래서 3을 달성 할 것 같습니다. 두 키 사이의 날짜 범위를 추출하기위한 두 번째 개인 대상 (포함). 출력되는 시간을 제외하고 출력되는 양에 따라 다릅니다. 나는 그것을 위해 사용할 것 dd입니다 ... 그것은 훌륭한 도구입니다! :)
Peter.O

30

원하는 것처럼 들립니다.

tail -c +1048576

또는 건너 뛰려는 바이트 수. 더하기 부호는 꼬리 대신 파일의 시작부터 끝이 아닌 측정을 지시합니다. GNU 버전의 tail을 사용하는 경우 다음과 같이 작성할 수 있습니다.

tail -c +1M

잘라낸 후 고정 된 수의 바이트를 얻으려면 나머지 모든 파일 대신 head를 통해 파이프하십시오.

tail -c +1048576 | head -c 1024

리눅스 / bash 유연성은 끔찍합니다 (Linux로 전환하는 데 너무 오랜 시간이 걸렸습니다). 나는 방금 akira의 대답을 받아 들였지만, 이것을 더 완전히 평가할 때까지 그것을 뽑았습니다. dd특정 바이트로 이동 tail하지만 (알 수없는) 줄 길이를 알 수없는 고통 코딩이며 선행 부분 줄을 제거하기 위해 sed를 호출하는 것입니다 ... 꼬리없이 고통없이 할 수있는 것처럼 보입니다. . 나는 머리가 꼬리에서 탭을 끄는 방법을 이해하지 못하지만 다음과 같은 것 같습니다. 내일 다시 가야 해요.
Peter.O

@ fred.bear : tail/ head라인 길이를 추측 할 수 없습니다. x 위치로 이동 한 다음 x의 왼쪽 또는 오른쪽을 볼 수 있습니다 \n. 프로그램이 무엇인지는 중요하지 않습니다. 따라서 두 경우 모두 x head로 이동하여 다음 줄 끝을 오른쪽으로 보는 데 사용 합니다.
akira

tail|head의 count = val에 대해 전혀 걱정하지 않아도 dd됩니다. 'dd'를 사용하면 충분한 데이터를 얻지 못하면 "게임 오버"입니다. 임의의 선 길이의 유연성이 뛰어납니다. 'dd'에 대해 "가장 가까운"전체 행과 오프셋을 반환하는 함수를 작성했지만 길이 문제를 피하고 싶습니다. 나는 이제 tail | head를 테스트했으며 처음에는 잘 수행되지만 (= 100MB까지), offset = 8GB ( 1 분 안에 가능)에서 한 번의 액세스에 대해 2 분이 걸리도록 크게 느려집니다. 더 작은 파일을 awk위해 .. 꼬리 / 머리 콤보를 알게 해 주셔서 감사합니다 :)
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

'분할'을 사용하면 모든 단일 바이트를 한 번 터치합니다. 그렇게하면 8GB 전체를 grep 할 수 있습니다.
akira

@sifusam .. 파일을 나누는 것이 아니라 이진 분할 검색을 수행하고 싶습니다. en.wikipedia.org/wiki/Binary_search_algorithm ... 그래서 다른 질문에 대한 좋은 대답이었습니다. 당신이 굴러 가기 위해 +1 ....
Peter.O

0

여기 내 스크립트가 있습니다. 첫 번째 필드가 내 번호와 일치하는 첫 줄을 찾고 있습니다. 행은 첫 번째 필드에 따라 정렬됩니다. dd를 사용하여 128K 블록의 첫 번째 줄을 확인한 다음 블록으로 이동하여 검색을 수행합니다. 파일이 1M 이상이면 효율성이 향상됩니다.

모든 의견이나 정정 부탁드립니다!

#!/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;};';

* 편집 * ** grep이 훨씬 빨라지고 더 잘 나옵니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.