﻿<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://purl.org/atom/ns#">
	<link xmlns="http://purl.org/atom/ns#" type="text/html" rel="alternate" href="http://sial.org/blog/" title="Jeremy Mates’s Blog"/>
	<title xmlns="http://purl.org/atom/ns#">Jeremy Mates’s Blog</title>
	<entry xmlns="http://purl.org/atom/ns#" xmlns:default="http://www.w3.org/1999/xhtml">
		<title xmlns="http://purl.org/atom/ns#">Perl One Liner Construction</title>
		<dc:subject>Perl</dc:subject>
		<dc:subject>Scripts</dc:subject>
		<summary xmlns="http://purl.org/atom/ns#">summary</summary>
		<content xmlns="http://purl.org/atom/ns#" mode="escaped">&lt;p&gt;Perl one liners require skill and imagination to construct. Consider the requirement to replace an arbitrary number of lines between a &lt;tt&gt;start&lt;/tt&gt; and an &lt;tt&gt;end&lt;/tt&gt; line with the output of a command. First, suitable input data must be generated: there is no better test than to run actual data through the devised solution. Spare your audience the untested guesses, and when ready, include the test code and data in your release, so that others can confirm the results, or think of cases your tests may have missed. The input data should include several lines of data to be replaced, as well as lines before and after the &lt;tt&gt;start&lt;/tt&gt; and &lt;tt&gt;end&lt;/tt&gt; tags to confirm the solution does not affect data it should not:&lt;/p&gt;
&lt;p style="font-family: &quot;Courier&quot;, &quot;Bitstream Vera Sans Mono&quot;, monospace; background-color: #efefef; padding: 0.5em; white-space: pre; border-color: #999; border-width: 1px; border-style: solid; clear: both; max-width: 50em;"&gt;$ &lt;kbd style="font-weight: bold;"&gt;&lt; input&lt;/kbd&gt;
first
start
replacethis
and this too
end
last&lt;/p&gt;

&lt;!-- technorati tags start --&gt;&lt;p style="text-align:right;font-size:10px;"&gt;Technorati Tags: &lt;a href="http://www.technorati.com/tag/Perl" rel="tag"&gt;Perl&lt;/a&gt;, &lt;a href="http://www.technorati.com/tag/scripts" rel="tag"&gt;scripts&lt;/a&gt;, &lt;a href="http://www.technorati.com/tag/shell" rel="tag"&gt;shell&lt;/a&gt;&lt;/p&gt;&lt;!-- technorati tags end --&gt;
&lt;br /&gt;
&lt;p&gt;Portions of the data will not be printed; therefore, the &lt;a href="http://search.cpan.org/perldoc/perlrun"&gt;&lt;tt&gt;-n&lt;/tt&gt; switch&lt;/a&gt; should be used to loop without printing.&lt;/p&gt;
&lt;p style="font-family: &quot;Courier&quot;, &quot;Bitstream Vera Sans Mono&quot;, monospace; background-color: #efefef; padding: 0.5em; white-space: pre; border-color: #999; border-width: 1px; border-style: solid; clear: both; max-width: 50em;"&gt;$ &lt;kbd style="font-weight: bold;"&gt;&lt;input perl -ne print&lt;/kbd&gt;
first
start
replacethis
and this too
end
last&lt;/p&gt;
&lt;p&gt;The arbitrary lines between &lt;tt&gt;start&lt;/tt&gt; and &lt;tt&gt;end&lt;/tt&gt; suggest the &lt;a href="http://search.cpan.org/perldoc/perlop"&gt;range operator&lt;/a&gt;, and otherwise to print lines outside this range. Memorizing the various operators and functions and knowing how to apply them to various tasks is an essential skill for Perl programming. The &lt;a href="http://www.amazon.com/o/ASIN/0596003137/sialorg-20"&gt;Perl Cookbook&lt;/a&gt; can help bridge a lack of skill, as it offers specific examples and solutions to those problems.&lt;/p&gt;
&lt;p style="font-family: &quot;Courier&quot;, &quot;Bitstream Vera Sans Mono&quot;, monospace; background-color: #efefef; padding: 0.5em; white-space: pre; border-color: #999; border-width: 1px; border-style: solid; clear: both; max-width: 50em;"&gt;$ &lt;kbd style="font-weight: bold;"&gt;&lt;input perl -ne &#39;if(/start/../end/)' \&lt;/kbd&gt;
  &lt;kbd style="font-weight: bold;"&gt;-e '{ ; } else { print }&#39;&lt;/kbd&gt;
first
last&lt;/p&gt;
&lt;p&gt;Next, the shell command. Backticks suffice here, as the command output can be passed directly to &lt;tt&gt;print&lt;/tt&gt;:&lt;/p&gt;
&lt;p style="font-family: &quot;Courier&quot;, &quot;Bitstream Vera Sans Mono&quot;, monospace; background-color: #efefef; padding: 0.5em; white-space: pre; border-color: #999; border-width: 1px; border-style: solid; clear: both; max-width: 50em;"&gt;$ &lt;kbd style="font-weight: bold;"&gt;&lt;input perl -ne &#39;if(/start/../end/)' \&lt;/kbd&gt;
  &lt;kbd style="font-weight: bold;"&gt;-e '{ print `pwd` } else { print }&#39;&lt;/kbd&gt;
first
/home/jmates/tmp
/home/jmates/tmp
/home/jmates/tmp
/home/jmates/tmp
last&lt;/p&gt;
&lt;p&gt;This reveals a bug, though, as the shell command is being executed for each line between and including the &lt;tt&gt;start&lt;/tt&gt; to &lt;tt&gt;end&lt;/tt&gt; lines. Since the command should be executed only once, the logical solution is a state variable that only allows the command to run once:&lt;/p&gt;
&lt;p style="font-family: &quot;Courier&quot;, &quot;Bitstream Vera Sans Mono&quot;, monospace; background-color: #efefef; padding: 0.5em; white-space: pre; border-color: #999; border-width: 1px; border-style: solid; clear: both; max-width: 50em;"&gt;$ &lt;kbd style="font-weight: bold;"&gt;&lt;input perl -ne &#39;if(/start/../end/)&#39; \&lt;/kbd&gt;
  &lt;kbd style="font-weight: bold;"&gt;-e &#39;{ $d++ || print `pwd` }&#39; \&lt;/kbd&gt;
  &lt;kbd style="font-weight: bold;"&gt;-e &#39;else { print }&#39;&lt;/kbd&gt;
first
/home/jmates/tmp
last&lt;/p&gt;
&lt;p&gt;This assignment relies on autovivication, where &lt;tt&gt;$d&lt;/tt&gt;, false by default, first fails the check, and allows the shell command to run. After the first check fails, &lt;tt&gt;$d&lt;/tt&gt; increments to a true value, and will therefore no longer allow the command to run. A full solution would also print the &lt;tt&gt;start&lt;/tt&gt; and &lt;tt&gt;end&lt;/tt&gt; tags, as the requirement called for only the text &lt;i&gt;between&lt;/i&gt; the tags to be replaced. That code is left as an exercise.&lt;/p&gt;
&lt;p&gt;A robust solution would check the shell command for errors, and perhaps also handle standard error output. The &lt;a href="http://sial.org/howto/perl/one-liner/"&gt;Perl one liners&lt;/a&gt; article includes a section on converting one liners to proper scripts.&lt;/p&gt;
		</content>
		<issued xmlns="http://purl.org/atom/ns#">2009-05-16T12:57:19-0700</issued>
		<link xmlns="http://purl.org/atom/ns#" type="text/html" rel="alternate" href="http://sial.org/blog/2009/05/perl_one_liner_construction.html" title=""/>
		<id xmlns="http://purl.org/atom/ns#">357</id>
	</entry>
</feed>
