2013-03-22 3 views
1

웹 사이트 마이그레이션을 위해 SQL 덤프 안에 fqdn을 교체해야합니다. 나는 STDIN을 취하고 대체되어야하는 도메인 이름을 포함하는 직렬화 된 문자열을 대체하고 스크립트에 전달되는 모든 인수로 바꾸고 STDOUT으로 출력해야하는 펄 필터를 작성했습니다. 필터 (이이 워드 프레스 덤프에서 가져온 것입니다,하지만 우리는 또한 드루팔을 수용하기로하고 다음과 같이 보일 수 있습니다 데이터를 전달됩니다 perl은 SQL 덤프에서 직렬화 된 문자열을 대체합니다.

my $search = $ARGV[0]; 
my $replace = $ARGV[1]; 
my $offset_s = length($search); 
my $offset_r = length($replace); 
my $regex = eval { "s\:([0-9]+)\:\\\"(https?\://.*)($search.*)\\\"" }; 

while (<STDIN>) { 
    my @fs = split(';', $_); 
    foreach (@fs) { 
     chomp; 
     if (m#$regex#g) { 
     my ($len, $extra, $str) = ($1, $2, $3); 
     my $new_len = $len - $offset_s + $offset_r; 
     $str =~ eval { s/$search/$replace/ }; 
     print 's:' . $new_len . ':' . $extra . $str . '\"'."\n"; 
     } 
    } 
} 

덤프

:

내가 지금까지 무엇을 가지고

$search에 마침표가없는 경우
INSERT INTO `wp_2_options` VALUES (1,'siteurl','http://to.be.replaced.com/wordpress/','yes'),(125,'dashboard_widget_options',' 
a:2:{ 
s:25:\"dashboard_recent_comments\";a:1:{ 
s:5:\"items\";i:5; 
} 
s:24:\"dashboard_incoming_links\";a:2:{ 
s:4:\"home\";s:31:\"http://to.be.replaced.com/wordpress\"; 
s:4:\"link\";s:107:\"http://blogsearch.google.com/blogsearch?scoring=d&partner=wordpress&q=link:http://to.be.replaced.com/wordpress/\"; 
} 
} 
','yes'),(148,'theme_175',' 
a:1:{ 
s:13:\"courses_image\";s:37:\"http://to.be.replaced.com/files/image.png\"; 
} 
','yes') 

정규식 작동합니다. 내가 즉 domain\.to\.be\.replaced 기간을 탈출 시도했습니다,하지만 그건. 아마 매우 로터리 속에서 이것을하고있어 작동하지 않았다 방법이나 명백한 무언가를 놓치기. 어떤 도움이 될 greatl y는 인정했다.

답변

2

정규 표현식에 변수가 들어 있기 때문에 (eval) 정규식을 평가할 필요가 없습니다. 또한 $search과 같은 변수의 메타 문자의 특수한 의미를 피하려면 quotemeta() 함수를 사용하거나 정규식 내에 \Q과 사이의 변수를 포함하여 이스케이프 처리하십시오. 그래서 대신 :

my $regex = eval { "s\:([0-9]+)\:\\\"(https?\://.*)($search.*)\\\"" }; 

사용 :

my $regex = qr{s\:([0-9]+)\:\\\"(https?\://.*)(\Q$search\E.*)\\\"}; 

또는

my $quoted_search = quotemeta $search; 
my $regex = qr{s\:([0-9]+)\:\\\"(https?\://.*)($quoted_search.*)\\\"}; 

그리고이 라인에 대한 충고 :

$str =~ eval { s/$search/$replace/ }; 
1

당신은 이스케이프 문자를 두 배로해야에 이스케이프 된 마침표를 포함 할 보간 문자열의 변수입니다.

domain\.to\.be\.replaced ->domain.to.be.replaced (원하지 않는)

domain\\.to\\.be\\.replaced 동안 ->domain\.to\.be\.replaced (올바른).

0

perl regex가 (동일한 직렬화 된 문자열에서) 여러 번 일치하는 문자열에서 DNS를 대체 ​​할 것인지 확신하지 못합니다.

나는이 문제와 관련하여 bash, sed 및 하나의 거대한 perl 정규식을 사용하여 스크립트로 요점을 만들었습니다. give it a try 일 수 있습니다.

내가 사용하는 정규식은 그런 일이 (lisibility에 대한 폭발과 가진 -7 도메인 이름 사이에 알려진 차이는 길이로) : 아마도 가장 좋은 일이지만 적어도 보인다되지 않습니다

perl -n -p -i -e '1 while s# 
    ([;|{]s:) 
    ([0-9]+) 
    :\\" 
    (((?!\\";).)*?) 
    (domain\.to\.be\.replaced) 
    (.*?) 
    \\";#"$1".($2-7).":\\\"$3new.domain.tld$6\\\";"#ge;' file 

을 그 직업을 g 옵션은 정리할 일련의 직렬화 된 문자열을 포함하는 행을 관리하고 while 루프는 일련의 DNS에서 여러 문자열이 포함 된 문자열에 대해 대체가 발생하지 않을 때까지 전체 작업을 다시 실행합니다. 나는 재귀 적으로 시도 할 정규 표현식의 팬이 아니다.

관련 문제