Суть того, как этого добиться, состоит в том, чтобы получить имена файлов в архиве для поиска и извлечь их содержимое для поиска, не извлекая ничего другого.Поскольку мы не хотим записывать в файловую систему, мы можем использовать флаг -O
для извлечения в стандартный вывод.
tar -tzf file.tar.gz | grep '\.txt' | xargs tar -Oxzf file.tar.gz | grep -B 3 "string-or-regex"
объединит все файлы в .tar.gzс именами, оканчивающимися на ".txt", и grep
их для данной строки, также выводя 3 предыдущие строки.Он не скажет вам, из какого файла в тарболе пришло какое-либо совпадение, и «три предыдущие строки» могут фактически исходить из предыдущего файла.
Вместо этого вы можете сделать:
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
, который будет учитывать границы файлов и сообщать имена файлов, но будет гораздо менее эффективным.
(-z
сообщает tar
, что он gzip
сжат. -t
перечисляет содержимое. -x
extracts. -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, и, таким образом, может повторять строки, которые находятся в пределах 3 строк двух разных совпадений.