bash中的PHP preg_replace,具体情况

时间:2012-07-04 01:42:14

标签: linux bash preg-replace sh

我需要清理一个包含PHP序列化值的mysql转储(我使用sed搜索/替换url)

在PHP中我会这样做:

<?php

$ret_string = preg_replace('!s:(\d+):"(.*?)";!e', "'s:'.mb_strlen('$2').':\"$2\";'", $string );

?>

你怎么在bash中这样做?

例如原始字符串:

a:3:{s:7:"string1";s:4:"test";s:3:"url";s:17:"http://myurl.com";s:7:"string2";s:‌​4:"test";} 

我已经用mynewurl.com取代了myurl.com所以它现在看起来像:

a:3:{s:7:"string1";s:4:"test";s:3:"url";s:17:"http://mynewurl.com";s:7:"string2";s:‌​4:"test";}

我需要更改的是字符串的长度,以反映新字符串的长度(s:17),以便最终字符串成为:

a:3:{s:7:"string1";s:4:"test";s:3:"url";s:19:"http://mynewurl.com";s:7:"string2"‌​;s:4:"test";}

我的sql转储中有很多这是文件系统上的文件。虽然域已更改,但URL可能有一个额外的路径,因此不同的字符串长度

2 个答案:

答案 0 :(得分:1)

在regexp中执行此操作的问题是regexp不适合结构化文本,如JSON或PHP序列化字符串。如果您知道输入数据总是遵循某种结构,那么您可以“伪造”某些东西,但随着时间的推移,随着时间的推移,代码编写会变得有问题。而且事情总会随着时间而改变。如果你能避免这种黑客攻击,最好这样做。

我们在这里试图解决的问题究竟是什么?您是否无法在需要进行此更改的主机上运行PHP?即使您使用一个很小的shell可执行PHP脚本来处理它,序列化数据也将更容易在PHP中处理。

[ghoti@pc ~]$ cat indexrepl
#!/usr/bin/env php
<?php

// Usage: indexrepl index newcontent [string]

if ($argc < 4) {
  $s='a:3:{s:7:"string1";s:4:"test";s:3:"url";s:16:"http://myurl.com";s:7:"string2";s:4:"test";}';
} else {
  $s=$argv[3];
}

$a=unserialize($s);
$a[$argv[1]]=$argv[2];

print serialize($a) . "\n";

[ghoti@pc ~]$ 
[ghoti@pc ~]$ 
[ghoti@pc ~]$ ./indexrepl url http://example.com/
a:3:{s:7:"string1";s:4:"test";s:3:"url";s:19:"http://example.com/";s:7:"string2";s:4:"test";}
[ghoti@pc ~]$ 
[ghoti@pc ~]$ s='a:3:{s:7:"string1";s:4:"test";s:3:"url";s:19:"http://example.com/";s:7:"string2";s:4:"test";}'
[ghoti@pc ~]$ ./indexrepl string1 foo "$s"
a:3:{s:7:"string1";s:3:"foo";s:3:"url";s:19:"http://example.com/";s:7:"string2";s:4:"test";}

UPDATE:将其包装在shell构造中,每条评论:

[ghoti@pc ~]$ cat strings.txt
a:1:{s:3:"foo";s:3:"bar";}
a:1:{s:3:"foo";s:3:"baz";}
a:1:{s:3:"foo";s:5:"snert";}
[ghoti@pc ~]$ while read line; do ./indexrepl foo test "$line"; done < strings.txt
a:1:{s:3:"foo";s:4:"test";}
a:1:{s:3:"foo";s:4:"test";}
a:1:{s:3:"foo";s:4:"test";}
[ghoti@pc ~]$ 

答案 1 :(得分:0)

我最终得到了一个php -r解决方案。在bash中这样做我认为会有很多行:

mv "$DATA_DIR/final.sql" "$DATA_DIR/final.sql.1"
php -r  "echo preg_replace('!s:(\\d+):\\\\\\\"(.*?)\\\\\\\";!e', \"'s:'.strlen( str_replace (array('\\\\r', '\\\\n', '\\\\t'), ' ', '\$2') ) .':\\\\\\\"\$2\\\\\\\";'\", file_get_contents('$DATA_DIR/final.sql.1') );" >"$DATA_DIR/final.sql"
rm "$DATA_DIR/final.sql.1";

这适用于我的情况。