FIND + PERL: как добавить непрерывный счетчик для всех случаев определенного тега в каталоге, полном файлов - PullRequest
0 голосов
/ 28 октября 2019

У меня есть тысячи файлов XML, и мне нужно добавить непрерывный инкрементный счетчик к каждому вхождению определенного тега во всех них. Другими словами, если в каждом имеется 10 файлов и 50 ящиков тега, счетчик должен перейти от 1 до 500, где 1-50 находится в первом файле, 51-100 во втором и т. Д.

Я использую find для получения всех файлов и Perl для выполнения операций поиска и замены внутри каждого файла. Базовый код, с которым я работаю, таков:

#!/bin/bash
find . -type f -name "*.xml" -exec perl -i -p0e "s#<tag>#<tag count=${COUNTER}>#gm" {} +`

Это должно принимать каждое вхождение <tag> и добавлять текущее значение счетчика, например, <tag counter=000001924>.

Проблема в том,что я не могу понять, как поддерживать значения счетчиков между файлами. Если я поставлю COUNTER=COUNTER+1 перед find, счетчик, очевидно, никогда не увеличится. Если я помещу его в код Perl, он сбрасывается в 0 для каждого файла.

И, к сожалению, все ответы, которые я могу найти, - это добавление счетчика к именам файлов , а не к что-то в файлах , что является другой проблемой.

Как я могу это сделать?

1 Ответ

4 голосов
/ 28 октября 2019

find -exec perl может запускаться perl любое количество раз, так что это не хорошо. Нам нужно убедиться, что запускается только один perl процесс (если только мы каким-то образом не сохраним счетчик где-нибудь в постоянном месте, как в файле).

Мы можем find напечатать имена файлов и прочитать их в perl, но в этом нет особого смысла, когда получить список имен файлов в Perl так же просто.

#!/usr/bin/perl

use strict;
use warnings;

use File::Find::Rule qw( );
use XML::LibXML      qw( );

my $counter = 0;
my $parser = XML::LibXML->new();

for my $qfn (
   File::Find::Rule
      ->file
      ->name("*.xml")
      ->in(".")
) {
   eval {
      my $doc = $parser->parse_file($qfn);
      $_->setAttribute("count", ++$counter) for $doc->findnodes("//tag");
      $doc->toFile($qfn, 0);
      return 1;
   }
      or warn("Error processing \"$qfn\": $@\n");
}

Вы можете сохранить это в файле, который вы можете просто выполнить, или вы можете обернутьв пределах perl -e'...'.

...