sed를 사용하여 여러 파일의 전체 HTML 블록을 교환하는 방법

sed를 사용하여 여러 파일의 전체 HTML 블록을 교환하는 방법

다음과 유사한 내용을 포함하는 HTML 페이지가 많이 있습니다.

<div class="wrapper">

<div class="aaa">
...lot of html1 here like div's/spans etc..
</div> <!-- end aaa -->

<div class="bbb">
...lot of html2 here
</div><!-- end bbb -->

</div>

div를 해당 콘텐츠와 함께 aaa 및 bbb 클래스로 완전히 바꿔야 합니다.

그래서 그것은 다음과 같습니다:

<div class="wrapper">

<div class="bbb">
...lot of html2 here
</div><!-- end bbb -->

<div class="aaa">
...lot of html1 here
</div> <!-- end aaa -->

</div>

노트:

1) 블록 사이의 빈 줄은 선택 사항입니다. 2) HTML에는 정확한 and
쌍만 포함되어 있으므로 다음 과 같은 상황 은 불가능합니다.aaabbbaaabbbaaa

그렇다면 어떤 매개변수를 전달해야 하는지 제안해 주실 수 있나요 sed? find모든 HTML 파일을 찾은 다음 sed실행 매개변수로 실행하는 데 사용하는 것 :

find . -iname "*.html" -exec sed -i '' 's/WHAT IS HERE / AND HERE /g' {} \;

이것이 가능하지 않지만 sed가능하다고 가정해 봅시다. awk귀하의 기대를 달성할 수 있는 최선의 방법에 대한 귀하의 생각을 공유해 주시면 기쁠 것입니다.

고쳐 쓰다:

다음은 실제 사례에 대한 링크입니다. http://pastebin.com/mdhJ9rtL

답변1

aaa이전 부분을 bbb그 뒤에 넣으 려면 다음을 수행하십시오.

sed -i '/<div class="aaa">/{
        :1
        /<\/div> <\!-- end aaa -->/!{N;b 1}
        /<\/div> <\!-- end aaa -->/{N;h}
        d}
        /<\/div><\!-- end bbb -->/{n;G}' *html

답변2

여기 또 다른 것이 있습니다 sed:

sed '/.*<div class="...">.*/{ h;s///;x;:n
     /<.div>/!N;/<!-- end/x;/<.div>/x;//!bn
    s/\(.*\).\(<div class=.*>\).*/\2\1/;x
     /<.div>[^>]*$/s/.//;H;x
}'

라인 으로 시작 class=.???.하여 가능한 한 많은 블록을 통과하세요. 각 쌍마다 위치가 바뀌게 됩니다. 다음은 몇 가지 예입니다.

sed일치하는 줄이 발견 되면 :

<div class=".\{3\}">

H...파일을 읽는 동안 이전 공간이 완전히 지워졌는지 확인한 다음 일치하는 줄을 만날 때까지 각 줄을 가져오기 시작합니다.

<.div>

...그리고...

<!-- end

...또는 전자일 수도 있습니다. 둘 다 일치하면 sed블록이 백업 버퍼에 저장되고 출력에서 ​​위치를 바꾸기 전에 두 번째 블록을 가져옵니다.

전자라면 블록의 위치에는 영향을 미치지 않습니다. 이러한 방식으로 일치하지 않는 쌍이 유지됩니다.

입력으로 주어진...

<div class="wrapper">
<div class="aaa"> first </div> <!-- end aaa -->
between
<div class="bbb"> swap two </div> <!-- end bbb -->
blocks
<div class="ccc"> mismatched </div> <!-- end ccc --> 
the end         
</div>

인쇄된다...

<div class="wrapper">
<div class="bbb"> swap two </div> <!-- end bbb -->
between
<div class="aaa"> first </div> <!-- end aaa -->
blocks
<div class="ccc"> mismatched </div> <!-- end ccc -->
the end
</div>

...주어진 경우:

<div class="wrapper">
<div class="aaa"> first </div> <!-- end aaa -->
between
<div class="bbb"> swap two </div> <!-- end bbb -->
blocks
<div class="ccc"> matched </div> <!-- end ccc --> 
the end
<div class="ddd"> now matched </div> <!-- end ddd -->
</div>

인쇄된다...

<div class="wrapper">
<div class="bbb"> swap two </div> <!-- end bbb -->
between
<div class="aaa"> first </div> <!-- end aaa -->
blocks
<div class="ddd"> now matched </div> <!-- end ddd -->
the end
<div class="ccc"> matched </div> <!-- end ccc -->
</div>

<div class=그리고 공간을 절약하기 위해 예제를 이렇게 압축했지만 시작 부분 과 <.div> <!-- end부분이 같은 줄에 있는지 여부는 실제로 중요하지 않습니다 .

<div class="wrapper">
<div class="aaa">

the first
block is here

</div> <!-- end aaa -->

these lines were
between aaa and bbb

<div class="bbb">

this is the second block
it should be swapped with the first

</div> <!-- end bbb -->

more
blocks
follow

<div class="ccc"> this is matched </div> <!-- end ccc -->
not the end
<div class="ddd">

this last block
is matched with the ccc line
</div> <!-- end ddd -->

this is the end
</div>

얻다...

<div class="wrapper">
<div class="bbb"> 

this is the second block
it should be swapped with the first

</div> <!-- end bbb -->

these lines were
between aaa and bbb

<div class="aaa"> 

the first
block is here

</div> <!-- end aaa -->

more
blocks
follow

<div class="ddd"> 

this last block
is matched with the ccc line
</div> <!-- end ddd -->
not the end
<div class="ccc"> this is matched </div> <!-- end ccc -->

this is the end
</div>

답변3

sed당신이 처벌을 추구하는 사람이 아니라면 이것은 적합하지 않습니다 . 적어도 보다 일반적인 경우에는 블록이 한 줄 이상으로 시작됩니다(또는 태그가 여러 줄로 분할되는데, 이는 XML/HTML에서 가능합니다).

이 작업을 수행하기 위해 XML 파서 이외의 다른 것을 사용해야 하는 경우(예, 일반적으로 입력을 수정하거나 손상된 부분을 제거하는 것이 더 나은 생각입니다) awk최소한 다음과 같은 것을 사용하십시오. 이러한 작업에 더 적합합니다 * ) . 일반적인 아이디어는 다음과 같습니다.

  1. 첫 번째 블록이 시작될 때까지 입력 줄을 인쇄합니다.
  2. 교환할 첫 번째 블록의 행을 누적합니다.
  3. 블록 사이에 라인을 축적합니다.
  4. 두 번째 블록의 행을 인쇄합니다.
  5. 3단계에서 쌓인 블록 사이의 줄을 인쇄합니다.
  6. 2단계에서 누적된 첫 번째 블록의 행을 인쇄합니다.
  7. 나머지를 인쇄하세요.

또한 확인하는 것을 잊지 마세요표준 SO Q&A.

* 내가 주장하는 이유: sed는 라인 지향적이고 단순함을 목표로 합니다(여행 비용은 변경될 수 있습니다.) 텍스트 변환. 이는 AWK(및 어느 정도 Perl)에서도 마찬가지지만 후자가 더 복잡한 스크립트를 작성하는 것이 더 간단합니다(여러 변수에 액세스하기 쉽고 필드로 자동 분할 등이 더 쉽습니다). 따라서 매우 잘 분리된 두 개의 청크만 교체해야 하고 다른 형식의 입력을 처리하기 위해 스크립트를 확장할 필요가 없다면 더 복잡한 언어가 아마도 더 나은 도구일 것입니다. 즉, Perl에는 모듈로 쉽게 사용할 수 있는 XML 파서가 있습니다.

답변4

정규식을 사용하여 HTML을 구문 분석하는 것은 분명히 권장되지 않습니다.

대신에 다음을 사용할 수 있습니다.&소스 파일이 유효한 XHTML인 경우:

xmlstarlet edit -L -u "//div[@class='a']" -v 'some inner HTML' file.xhtml

유효한 XHTML이 아닌 경우 다음 Perl 코드를 수정해 보십시오.

use strict;
use warnings;
use 5.008;

use File::Slurp 'read_file';
use HTML::TreeBuilder;

sub replace_keyword
{
  my $elt = shift;

  return if $elt->is_empty;

  $elt->normalize_content;      # Make sure text is contiguous

  my $content = $elt->content_array_ref;

  for (my $i = 0; $i < @$content; ++$i) {
    if (ref $content->[$i]) {
      # It's a child element, process it recursively:
      replace_keyword($content->[$i])
          unless $content->[$i]->tag eq 'a'; # Don't descend into <a>
    } else {
      # It's text:
      if ($content->[$i] =~ /here/) { # your keyword or regexp here
        $elt->splice_content(
          $i, 1, # Replace this text element with...
          substr($content->[$i], 0, $-[0]), # the pre-match text
          # A hyperlink with the keyword itself:
          [ a => { href => 'http://example.com' },
            substr($content->[$i], $-[0], $+[0] - $-[0]) ],
          substr($content->[$i], $+[0])   # the post-match text
        );
      } # end if text contains keyword
    } # end else text
  } # end for $i in content index
} # end replace_keyword


my $content = read_file('foo.shtml');

# Wrap the SHTML fragment so the comments don't move:
my $html = HTML::TreeBuilder->new;
$html->store_comments(1);
$html->parse("<html><body>$content</body></html>");

my $body = $html->look_down(qw(_tag body));
replace_keyword($body);

# Now strip the wrapper to get the SHTML fragment back:
$content = $body->as_HTML;
$content =~ s!^<body>\n?!!;
$content =~ s!</body>\s*\z!!;

다음에서 빌림https://stackoverflow.com/questions/3900870/how-can-i-modify-html-files-in-perl

관련 정보