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