我需要清理一个包含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可能有一个额外的路径,因此不同的字符串长度
答案 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";
这适用于我的情况。