Нужна помощь в создании подкаталогов для хранения файлов с датами

Приведенная ниже программа TXR Lisp, называемая pcap.tl, используется следующим образом:

$ tcpdump -s 1024 -w - | ~/txr/txr pcap.tl

Он анализирует вывод формата pcap с помощью -wи выдает вывод, подобный:

192.168.1.102 --> 192.168.1.146
  ether hdr: #S(eth-header dst-mac #(8 0 39 249 113 4) src-mac #(0 30 79 164 102 184) eth-type ETH_IPV4)
  ipv4 hdr:  #S(ipv4-header ihl 5 ver 4 ecn 0 dscp 0 len 101 ident 7434 fragoffs-hi 0 flags 2
               fragoffs-lo 0 ttl 64 proto 6 hdr-sum 39232 src-ip 3232235878
               dst-ip 3232235922)
  ipv4 payload as text: P��.;;�.�+i�.6�...
KK-?9rrt2b
春が来た (Haru-ga Kita/Spring has Com

Код использует объявления типа FFI для определения типов структуры, соответствующих файлу pcap и формату пакета, заголовкам Ethernet и заголовкам ipv4. Заголовок ipv4 определяется двумя разными способами для машин с прямым порядком байтов и с прямым порядком байтов, поскольку он зависит от битовых полей.

Получаем всю полезную нагрузку IPv4 в виде данных UTF -8, декодируем их, заменяем управляющие символы точками и печатаем.

(defvarl big-endian-p (= 1 (ffi-get (ffi-put 1 (ffi be-uint32)) (ffi uint32))))
(defvarl little-endian-p (not big-endian-p))

(typedef ll-t (enumed uint32 ll-t
                DLT_NULL DLT_EN10MB))

(typedef eth-t (enumed be-uint16 eth-t
                 (ETH_IPV4 #x0800)
                 (ETH_ARP  #x0806)
                 (ETH_IPV6 #x08DD)))

(typedef pcap-header (struct pcap-header
                       (magic uint32)
                       (majver uint16)
                       (minver uint16)
                       (tzoffs uint32)
                       (tzprec uint32)
                       (snaplen uint32)
                       (lltype ll-t)))

(typedef pkt-header (struct pkt-header
                      (tsec uint32)
                      (tfrac uint32)
                      (trunclen uint32)
                      (origlen uint32)))


(typedef eth-header (struct eth-header
                      (dst-mac (array 6 uint8))
                      (src-mac (array 6 uint8))
                      (eth-type eth-t)))

(cond
  (big-endian-p
    (typedef ipv4-header (struct ipv4-header
                           (ver (bit 4 uint8))
                           (ihl (bit 4 uint8))
                           (dscp (bit 6 uint8))
                           (ecn (bit 2 uint8))
                           (len uint16)
                           (ident uint16)
                           (flags (bit 3 uint8))
                           (fragoffs-hi (bit 5 uint8))
                           (fragoffs-lo uint8)
                           (ttl uint8)
                           (proto uint8)
                           (hdr-sum uint16)
                           (src-ip uint32)
                           (dst-ip uint32))))
  (little-endian-p
    (typedef ipv4-header (struct ipv4-header
                           (ihl (bit 4 uint8))
                           (ver (bit 4 uint8))
                           (ecn (bit 2 uint8))
                           (dscp (bit 6 uint8))
                           (len be-uint16)
                           (ident be-uint16)
                           (fragoffs-hi (bit 5 uint8))
                           (flags (bit 3 uint8))
                           (fragoffs-lo uint8)
                           (ttl uint8)
                           (proto uint8)
                           (hdr-sum be-uint16)
                           (src-ip be-uint32)
                           (dst-ip be-uint32)))))

;; Look for IPv4 packets and print headers
(defun decode-packet (phdr buf)
  (let ((eh (ffi-get buf (ffi eth-header))))
    (unless (eq eh.eth-type 'ETH_IPV4)
      (return-from decode-packet))
    (let* ((ih (ffi-get buf (ffi ipv4-header) (sizeof eth-header)))
           (hdrsz (+ (sizeof eth-header) (sizeof ipv4-header)))
           (len (- (length buf) hdrsz))
           (body (carray-buf buf (ffi char) hdrsz))
           (rawtext (carray-get body))
           (text (mapcar (iffi [andf chr-iscntrl [notf chr-isspace]] (ret #\.))
                         rawtext)))
      (put-line `@(str-inaddr ih.src-ip) --> @(str-inaddr ih.dst-ip)`)
      (put-line `  ether hdr: @eh`)
      (put-line `  ipv4 hdr:  @ih`)
      (put-line `  ipv4 payload as text: @text`))))

;; main program
(let ((*stdin* (open-fileno (fileno *stdin*) "rbu")) ;; binary, unbuffered
      (hdr (new pcap-header))
      (hdr-buf (make-buf (sizeof pcap-header)))
      (phdr (new pkt-header))
      (phdr-buf (make-buf (sizeof pkt-header)))
      (pay-buf (make-buf 65536)))

  ;; read pcap file header
  (when (< (fill-buf hdr-buf) (sizeof pcap-header))
    (return))

  ;; decode to structure
  (ffi-in hdr-buf hdr (ffi pcap-header) t)

  (unless (eq hdr.lltype 'DLT_EN10MB)
    (put-line "can only deal with Ethernet frames")
    (exit nil))

  ;; read and decode packets
  (while t
    (when (< (fill-buf phdr-buf) (sizeof pkt-header))
      (return))
    (ffi-in phdr-buf phdr (ffi pkt-header) t)
    (buf-set-length pay-buf phdr.trunclen)
    (when (< (fill-buf pay-buf) phdr.trunclen)
      (return))
    (decode-packet phdr pay-buf)))

В этих строках происходит действие декодирования UTF -8:

       (body (carray-buf buf (ffi char) hdrsz))
       (rawtext (carray-get body))

bodyпривязан к объекту carray, наложенному на buf, со смещением hdrszдля отправки заголовка Ethernet и IPV4. Тип элемента — char. Он занимает всю оставшуюся часть буфера после заголовка.

Затем (carray-get body)превращает все внешнее значение в строку Лиспа. Поскольку тип элемента — char, преобразование UTF -8 запускает в :особое поведение для массивов char. Если бы тип был bchar, он просто принял бы байты как символы 1 :1. Если бы тип был wchar, то массив был бы из wchar_tсимволов, соответственно преобразованных в строку. Чтобы получить вектор числовых байтов вместо строки, мы можем сделать тип элемента ucharили uint8.

Эту программу легко расширить для обработки TCP, UDP, IPv6 и всего, что необходимо. Он может искать определенные совпадения в определенных полях заголовка.

1
16.10.2019, 00:37
2 ответа

Вы можете перебрать имена, разделить имя на -, затем mkdir -pсоздать каталоги, если они не существуют, и, наконец, переместить. Примерно так:

for file in *msg; do 
    IFS="-" read -r year month day rest  <<< "$file"
    dir="$year/$month/$day/" 
    mkdir -p -- "$dir"
    mv -- "$file" "$dir"
done
3
27.01.2020, 23:15

Это довольно легко сделать с помощью инструмента переименования perl (, а НЕ инструмента переименования из пакета util -linux ). например.

Настройка:

$ touch 2019-05-01-00.34.00.msg 2019-05-02-00.36.00.msg 2019-06-14-01.38.00.msg
$ ls -l
total 2
-rw-r--r-- 1 cas cas 0 Oct 16 20:56 2019-05-01-00.34.00.msg
-rw-r--r-- 1 cas cas 0 Oct 16 20:56 2019-05-02-00.36.00.msg
-rw-r--r-- 1 cas cas 0 Oct 16 20:56 2019-06-14-01.38.00.msg

Переименовать:

rename  -n '
  use File::Path qw(make_path);

  if (-f $_ && m/^\d{4}-\d{2}-\d{2}-/) {
    my ($y,$m,$d,$f) = split /-/,$_,4;
    make_path("$y/$m/$d");
    $_ = "$y/$m/$d/$f";
  }' *.msg

Этот сценарий начинается с игнорирования имен файлов, которые не являются обычными файлами(-f)или не соответствуют шаблону ^YYYY-MM-DD-. Это предотвращает создание нежелательных каталогов при вводе мусора.

Имя файла разбивается на четыре элемента. Первые 3 — это год, месяц и день, встроенные в имя файла ($y, $mи $d), а 4-й — оставшаяся часть имени файла($f).

Он использует функцию make_path()из стандартного модуля Файл ::Путь для рекурсивного создания каталогов для YYYY/, YYYY/MM/и YYYY/MM/DD/(, подобно опции -pмодуля команда mkdir). Вместо этого я мог бы запустить Perl-функцию mkdir()три раза, но предпочел использовать File::Path.

Затем он переименовывает (, т.е. перемещает )файл в правильный каталог, устанавливая $_равным"$y/$m/$d/$f"

Это ключ к тому, как работает perl rename. Вы можете использовать любой perl-код, от простого s/foo/bar/поиска в стиле -и -замены до сценариев, намного более сложных, чем тот, что в этом ответе. Если код изменится $_, то файл будет переименован в это имя. Если $_не изменено, оно не переименовывается.

ПРИМЕЧАНИЕ. :этот один -вкладыш использует вариант renameи -n, так что работает только всухую -. Чтобы он действительно переименовывал файлы, удалите -nили измените его на -vдля подробного вывода, например:

2019-05-01-00.34.00.msg renamed as 2019/05/01/00.34.00.msg
2019-05-02-00.36.00.msg renamed as 2019/05/02/00.36.00.msg
2019-06-14-01.38.00.msg renamed as 2019/06/14/01.38.00.msg

Кстати, имена файлов могут быть предоставлены в команде -в строке (, как показано выше ), или путем передачи в сценарий(renameимеет параметр -0, чтобы он мог принимать ввод от, например find... -print0или что-то еще, что может вывести список имен файлов, разделенных NUL -).

Наконец,renameне будет не перезаписывать существующие файлы, если только вы не укажете это с помощью опции -f, также известной как --force.

2
27.01.2020, 23:15

Теги

Похожие вопросы