Tar.gzファイルがたくさんあるので、tar.gzedでない場合と同じように、「grepsomething * -Rin」を実行したいと思います。 tar.gzedをそのままにしておきたいのですが、grepをオンザフライで実行し、ファイルと行番号がプレフィックスとして付いたgrepの出現箇所を見つけます。
何かのようなもの:
grep mytoken1 * .tar.gz -Rin
次のようなものを取得します。
my1.tar.gz、dir1/file2:123:mytoken1はこの行にあります my2.tar.gz、dir2/file3:233:mytoken1もこの別の行にあります [...]
これを行う方法はありますか?
zgrep(または、-Zフラグを指定したgrep)を使用すると、圧縮ファイルをgrepできます。必要な情報の多くがわかると思いますが、これでは、ファイル名を確認する必要があります。ヘッダー:(
。tarまたは.gzファイル内を検索するUnixスクリプト :
スクリプト :
for file in $(tar -tzf file.tar.gz | grep '\.txt'); do
tar -Oxzf file.tar.gz "$file" | grep -B 3 --label="$file" -H "string-or-regex"
done
ファイルの境界を尊重し、ファイル名を報告します。 | grep '\.txt
パーツは、ニーズに合わせて調整することも、削除することもできます。
(-z
はtar
にgzip
圧縮されていることを通知します。-t
は内容を一覧表示します。-x
は抽出します。-O
は標準出力にリダイレクトします。古いtar
sには-O
または-z
フラグがない可能性があり、-
のないフラグが必要になります。例:tar tz file.tar.gz
)
Grepがこれらのフラグをサポートしていない場合は、awkを使用できます。
#!/usr/bin/awk -f
BEGIN { context=3; }
{ add_buffer($0) }
/pattern/ { print_buffer() }
function add_buffer(line)
{
buffer[NR % context]=line
}
function print_buffer()
{
for(i = max(1, NR-context+1); i <= NR; i++) {
print buffer[i % context]
}
}
function max(a,b)
{
if (a > b) { return a } else { return b }
}
これは、grep -Bとは異なり、隣接する一致を合体させないため、2つの異なる一致の3行以内にある行を繰り返すことができます。
1つの方法は、このクイックハックを使用することです。
#!/usr/bin/Ruby
=begin
Quick-and-dirty way to grep in *.tar.gz archives
Assumption:
each and every file read from any of the supplied tar archives
will fit into memory. If not, the data reading has to be rewritten
(a proxy that reads line-by-line would have to be inserted)
=end
require 'rubygems'
gem 'minitar'
require 'zlib'
require 'archive/tar/minitar'
if ARGV.size < 2
STDERR.puts "#{File.basename($0)} <regexp> <file>+"
exit 1
end
regexp = Regexp.new(ARGV.shift, Regexp::IGNORECASE)
for file in ARGV
zr = Zlib::GzipReader.new(File.open(file, 'rb'))
Archive::Tar::Minitar::Reader.new(zr).each do |e|
next unless e.file?
data = e.read
if regexp =~ data
data.split(/\n/).each_with_index do |l, i|
puts "#{file},#{e.full_name}:#{i+1}:#{l}" if regexp =~ l
end
end
end
end
これは、アーカイブの各ファイルがメモリに読み込まれるため(実際には2回)、より大きなアーカイブに推奨するということではありません。
もう少しメモリ効率の高いバージョンが必要な場合は、e.read
ループの別の実装を使用するか、おそらく完全に別の言語を使用する必要があります。 ;)
あなたが本当に興味を持っているなら、私はそれをもう少し効率的にすることができます...しかし、それは生の速度の点で、Cや他のコンパイルされた言語とは間違いなく比較されません。
これは非常に難しいと思います。
実際、tarは基本的に、ヘッダーが追加された、すべてのインクルードファイルの連結です。したがって、基本的にはgrep-in-tar
関数を記述して、それを処理し、ファイルと行番号に関する情報を提供できます(ヘッダーの読み取りと行番号の減算を伴う基本的なgrep)。私はそのようなプログラムについて聞いたことがありません。
問題はgzipにあります。これは圧縮形式であるため、コンテンツにアクセスする場合は解凍する必要があります。
gunzip -c files.tgz | grep-in-tar
あなたがやりたいことをする方法になるでしょう。現時点ではgunzip -c files.tgz | grep -Rin
を試すことができますが、バイナリファイルが一致すると表示されます。
* nixツールへのモジュラーアプローチは、grep/tar/zcatでこれを効率的に行う簡単な方法がないことを意味します。理想的には、ファイルを1回だけ解凍し、各tarファイルを1回のパスで処理する必要があります。これが私の試みですtgz-grep:
#!/usr/bin/python
import re,sys,tarfile
exp=re.compile(sys.argv[1])
tarfiles=sys.argv[2:]
for tfile in tarfiles:
tar=tarfile.open(tfile, mode='r|gz')
for file in tar:
name=file.name
count=0
for line in tar.extractfile(file):
count += 1
if exp.search(line):
print "%s,%s:%d:%s" % (tfile, name, count, line),
注:これは、ディレクトリ再帰(-R)やcase-insensitvity(-i)、またはGNU grepでサポートされている他のオプションは実行しませんが、追加するのは難しいことではありません。