Как я могу удалить в syslog.gz, используя grep для поиска строк? - Linux - PullRequest
0 голосов
/ 06 августа 2020

Я написал программу, которая ищет самые старые журналы, а затем я хочу проверить журналы, если есть, например, журналы с даты «30 июля 22:40». Я хочу удалить эти журналы. Но я не нашел ничего подобного ни здесь, ни где-либо еще. Не могли бы вы мне помочь?

var = subprocess.Popen('find /var/log/syslog* -mtime +%i' % specific_delete_range, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
out, err = var.communicate()
out = out.decode('ascii')

for line in out.split():
    firstresult.append(line)

for element in firstresult:
    with gzip.open(element, 'rb') as f:
        for line in f:
            if my_str_as_bytes in line:
                rightlines.append(line)

Итак, строки, которые находятся в списке "rightlines", должны быть удалены.

Ответы [ 2 ]

0 голосов
/ 06 августа 2020

В каком-то смысле делать это в Python - это слегка безумие, когда это намного проще сделать лаконично в сценарии оболочки. Но вот go при рефакторинге вашего кода.

Обычно вам следует избегать subprocess.Popen(), если можете; ваш код был бы проще и понятнее c с subprocess.run(). Но в этом случае, когда find потенциально может возвращать много совпадений, мы можем захотеть обработать файлы так, как они сообщаются, вместо того, чтобы ждать, пока подпроцесс завершит sh, а затем собрать его вывод. Используя код из этого ответа на переполнение стека и адаптируясь в соответствии с Фактическое значение 'shell = True' в подпроцессе , чтобы избежать shell=True, попробуйте что-то вроде

#!/usr/bin/env python3
from subprocess import Popen, PIPE
import gzip
from tempfile import NamedTemporaryFile
import shutil
import os


with Popen(
        ['find' '/var/log', '--name=syslog*', '-mtime', '+' +  specific_delete_range],
        stdout=PIPE, bufsize=1, text=True) as p:
    for filename in p.stdout:
        filename = filename.rstrip('\n')
        temp = NamedTemporaryFile(delete=False)
        with gzip.open(filename, 'rb') as f, gzip.open(temp, 'wb') as z:
            for line in f:
                if my_str_as_bytes not in line:
                    z.write(line)
        os.unlink(filename)
        shutil.copy(temp, filename)
        os.unlink(temp)

С text=True нам не нужно decode вывод из Popen. Строки из gzip по-прежнему являются двоичными байтами; мы могли бы, конечно, их декодировать, но вместо этого кодирование строки поиска в байты, как вы это сделали, более эффективно.

Суть в том, что мы используем временный файл для отфильтрованного результата, а затем перемещаем его обратно поверх исходного файла, как только мы его закончим.

NamedTemporaryFile имеет некоторые печальные особенности на Windows, но, к счастью для вас, вы не на Windows.

0 голосов
/ 06 августа 2020

Невозможно «удалить строки» в середине файла. Даже если бы это было возможно для обычного файла, это было бы невозможно сделать для сжатого файла, потому что сжатый файл состоит из «блоков», и весьма вероятно, что блоки не будут выровнены по границам строк.

В качестве альтернативы рассмотрите возможность извлечения содержимого, которое нужно оставить в файле, в новый файл, а затем переименовать новый файл, чтобы заменить старый файл.

Следующий сценарий bash ищет шаблон «P "в заархивированных файлах журнала и замените содержимое новым файлом, в котором нет строк с шаблоном" P ".

Примечание: сценарий не обрабатывает несжатый файл (аналогично тому, как работает сценарий OP ). Шаблон / var / log / syslog * был изменен для выбора только сжатых файлов (/var/log/syslog*.gz). Может потребоваться корректировка в зависимости от фактического суффикса, используемого для сжатых файлов.

days=30   # Change to whatever file age
P="Jul 30 22:40"    # Pattern to remove
P=
for file in $(zfgrep -l "$P" $(find /var/log/syslog*.gz -mtime +$days)) ; do
    # Extract content, re-compress and overwrite old files
    zfgrep -v "$P" $file | gzip > $file.new && mv $file.new $file
done
...