{"id":765,"date":"2010-08-11T12:57:10","date_gmt":"2010-08-11T11:57:10","guid":{"rendered":"http:\/\/www.thomaskeller.biz\/blog\/?p=765"},"modified":"2010-08-17T10:03:36","modified_gmt":"2010-08-17T09:03:36","slug":"search-and-replace-multiple-lines-across-many-files","status":"publish","type":"post","link":"https:\/\/www.thomaskeller.biz\/blog\/2010\/08\/11\/search-and-replace-multiple-lines-across-many-files\/","title":{"rendered":"Search and replace multiple lines across many files"},"content":{"rendered":"<p>sed is usually my favourite tool to search and replace things from the command line, but sometimes Perl&#8217;s regexes are far more convenient to use. Recently I found out another reason why Perls <code>-pi -e<\/code> is superior over plain sed: when you want to change multiple lines in a document!<\/p>\n<p>Imagine you have hundreds of source code files where somebody once had the great idea to add a ___version___ property into each class:<\/p>\n<pre lang=\"java\">\r\npublic class Foo\r\n{\r\n    private static final String ___version___ = \"$Version:$\";\r\n    \r\n    \/\/ other stuff\r\n}\r\n<\/pre>\n<p>With Perl the line in question is easy to remove:<\/p>\n<pre lang=\"bash\">\r\n$ for file in $(find . -name \"*.java\"); do \\\r\n   cp $file $file.bkp; perl -pi -e \\\r\n      \"s\/\\s*public.+___version___.+\\n\/\/g\" \\\r\n   < $file.bkp > $file; rm $file.bkp; done\r\n<\/pre>\n<p>But, there is one problem: Perl processes each line of the file separately when it slurps in the file, which results in unwanted empty lines:<\/p>\n<pre lang=\"java\">\r\npublic class Foo\r\n{\r\n    \r\n    \/\/ other stuff\r\n}\r\n<\/pre>\n<p>Then I stumbled upon <a href=\"http:\/\/www.debian-administration.org\/articles\/298\">this article<\/a> and the solution is to set a special input separator to let Perl slurp in the file as a whole:<\/p>\n<pre lang=\"bash\">\r\n$ for file in $(find . -name \"*.java\"); do \\\r\n   cp $file $file.bkp; perl -p0777i -e \\\r\n     \"s\/\\s*public.+___version___.+\\n(\\s*\\n)*\/\\n\/g\" \\\r\n   < $file.bkp > $file; rm $file.bkp; done\r\n<\/pre>\n<p>and voila, we get what we want:<\/p>\n<pre lang=\"java\">\r\npublic class Foo\r\n{\r\n    \/\/ other stuff\r\n}\r\n<\/pre>\n<p>Digging a little deeper what <code>-0777<\/code> actually means leads us to <code>perlrun(1)<\/code>:<\/p>\n<blockquote><p>\nThe special value 00 will cause Perl to slurp files in paragraph mode. The value 0777 will cause Perl to slurp files whole because there is no legal byte with that value.\n<\/p><\/blockquote>\n<p>Another day saved &#8211; thanks to Perl!<\/p>\n<p>And while we&#8217;re at it, have a look at Rakudo Star, the best Perl 6 compiler which was released just recently. Perl 6 is in my humble opinion one of the well-designed languages I&#8217;ve came across so far, so if you find some time, go over and read the last <a href=\"http:\/\/perl6advent.wordpress.com\/2009\/12\/01\/day-1-getting-rakudo\/\">christmas special<\/a>, its really worth it!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>sed is usually my favourite tool to search and replace things from the command line, but sometimes Perl&#8217;s regexes are far more convenient to use. Recently I found out another reason why Perls -pi -e is superior over plain sed: when you want to change multiple lines in a document! Imagine you have hundreds of &hellip; <a href=\"https:\/\/www.thomaskeller.biz\/blog\/2010\/08\/11\/search-and-replace-multiple-lines-across-many-files\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Search and replace multiple lines across many files<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,25],"tags":[],"class_list":["post-765","post","type-post","status-publish","format-standard","hentry","category-coding","category-tips"],"_links":{"self":[{"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/posts\/765","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/comments?post=765"}],"version-history":[{"count":8,"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/posts\/765\/revisions"}],"predecessor-version":[{"id":773,"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/posts\/765\/revisions\/773"}],"wp:attachment":[{"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/media?parent=765"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/categories?post=765"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.thomaskeller.biz\/blog\/wp-json\/wp\/v2\/tags?post=765"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}