1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

巨大なテキストファイルをメモリに読み込まずに grep し、ファイル先頭からのバイト数を取得する【Linux コマンド + PHP】

Posted at

--byte-offset オプション

$ grep -o "apple" --byte-offset input.txt
4:apple
25:apple

バイト数だけ表示する

$ grep -o "apple" --byte-offset input.txt | grep -oP '[0-9]+'
4
25

オプションの簡単な説明

コマンド オプション 説明
grep -o マッチした箇所のみを抽出
--byte-offset ファイル先頭からマッチした箇所までのバイト数を表示する
-o オプションがない場合、行頭までのバイト数)
-P 正規表現を使用して検索

コマンド使用例 : apple から orange の前まで抽出する (PHP)

$ cat input.txt 
foo
apple
bar
orange
baz
apple
hoge
fuga
piyo
orange
<?php

// ファイル先頭から apple, orange までのバイト数を取得
exec('grep -o "apple" --byte-offset input.txt | grep -oP "[0-9]+"', $apple);
exec('grep -o "orange" --byte-offset input.txt | grep -oP "[0-9]+"', $orange);

// apple から orange の前までをファイルから読み込む
$file = fopen("input.txt", "r");
fseek($file, intval($apple[0]));
$substr = fread($file, intval($orange[0]) - intval($apple[0]));
fclose($file);

print(json_encode($substr) . "\n");  // => "apple\nbar\n"

シークする場合 (dd)

たとえば先頭の 5 バイトをスキップする場合、以下のようになります。

$ dd if=input.txt iflag=skip_bytes skip=5 2>/dev/null \
    | grep -o "apple" --byte-offset --max-count=1 \
    | grep -oP '[0-9]+' \
    | head -n 1
20

※ 出力には dd でスキップした分のバイト数が含まれていないため、ファイル先頭からのバイト数を取得するにはこれを加算する必要があります。

オプションの簡単な説明

コマンド オプション 説明
dd if= 読み込む対象のファイル
of= 読み込んだ内容の出力先、指定しない場合は stdout
iflag=skip_bytes skip の値をバイト数で指定する
skip= if の先頭から指定した長さをスキップして読み込む
grep -o マッチした箇所のみを抽出
--byte-offset ファイル先頭からマッチした箇所までのバイト数を表示する
-o オプションがない場合、行頭までのバイト数)
--max-count= 検索した行数のうちヒットした行数が指定した数に達したら終了する
-P 正規表現を使用して検索

コマンド使用例 : baz より後の apple から orange の前まで抽出する (PHP)

$ cat input.txt 
foo
apple
bar
orange
baz
apple
hoge
fuga
piyo
orange
<?php

exec('grep -o "baz" --byte-offset input.txt | grep -oP "[0-9]+"', $baz);

$seekBytes = intval($baz[0]) + 1;

exec('dd if=input.txt iflag=skip_bytes skip=' . $seekBytes . ' 2>/dev/null | grep -o "apple" --byte-offset --max-count=1 | grep -oP "[0-9]+" | head -n 1', $apple);
exec('dd if=input.txt iflag=skip_bytes skip=' . $seekBytes . ' 2>/dev/null | grep -o "orange" --byte-offset --max-count=1 | grep -oP "[0-9]+" | head -n 1', $orange);

$fromBytes = intval($apple[0]) + $seekBytes;
$toBytes = intVal($orange[0]) + $seekBytes;

$file = fopen("input.txt", "r");
fseek($file, $fromBytes);
$substr = fread($file, $toBytes - $fromBytes);
fclose($file);

print(json_encode($substr) . "\n");  // => "apple\nhoge\nfuga\npiyo\n"

その他備考

  • unicode 以外の shift-jis などで検索すると正常にヒットしない可能性があります
  • また、ユーザーからの入力をどうしてもコマンドに含める必要がある場合はエスケープに注意してください
  • 入力ファイル内の一つの行内で複数箇所がヒットすると、 --max-count=1 を指定していても複数の結果が返ってくるようです
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?