<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>
<channel>
	<title>Netflow Developments &#187; script</title>
	<atom:link href="http://blog.netflowdevelopments.com/tag/script/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.netflowdevelopments.com</link>
	<description>The latest and greatest happenings in the world of Science, Technology and everything else Geek</description>
	<lastBuildDate>Mon, 06 Feb 2012 02:48:41 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Automatically blocking brute-force attacks on your FreeBSD server</title>
		<link>http://blog.netflowdevelopments.com/2011/08/01/automatically-blocking-brute-force-attacks-on-your-freebsd-server/</link>
		<comments>http://blog.netflowdevelopments.com/2011/08/01/automatically-blocking-brute-force-attacks-on-your-freebsd-server/#comments</comments>
		<pubDate>Mon, 01 Aug 2011 18:23:21 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[Linux / Freebsd]]></category>
		<category><![CDATA[attack]]></category>
		<category><![CDATA[block]]></category>
		<category><![CDATA[brute force]]></category>
		<category><![CDATA[cron]]></category>
		<category><![CDATA[firewall]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[ifpw]]></category>
		<category><![CDATA[invalid login]]></category>
		<category><![CDATA[IP]]></category>
		<category><![CDATA[password]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[ssh]]></category>
		<guid isPermaLink="false">http://blog.netflowdevelopments.com/?p=696</guid>
		<description><![CDATA[I was going through my auth.log today and noticed that a simple brute-force attack was underway.  a few hundred attacks from IP&#8217;s originating out of HANKUK UNIVERSITY OF FOREIGN STUDIES in Korea(220.67.126.35), Sun Network in China(121.127.231.251) and finally from Vodaphone in Italy(2.40.63.99).  I&#8217;m not concerned about them actually breaking through as there are no open accounts [...]]]></description>
			<content:encoded><![CDATA[<p>I was going through my auth.log today and noticed that a simple brute-force attack was underway.  a few hundred attacks from IP&#8217;s originating out of HANKUK UNIVERSITY OF FOREIGN STUDIES in Korea(220.67.126.35), Sun Network in China(121.127.231.251) and finally from Vodaphone in Italy(2.40.63.99).  I&#8217;m not concerned about them actually breaking through as there are no open accounts or guessable passwords anywhere on my system however they are causing a bit of overhead on my server with 60-80 login attempts.</p>
<p>So I went googling around to find a good way to monitor login activity and ban IP&#8217;s for people who have more than 7 failed logins.  I should note here that the best bet would be to have an IP whitelist that only allows ssh connections from specified IP&#8217;s but I&#8217;m jumping all over the place so often that that&#8217;s a bit of a pain in the ass, which leads me to the following solution found herE:</p>
<p style="text-align: center;"><a href="http://www.freebsdwiki.net/index.php/Block_repeated_illegal_or_failed_SSH_logins">http://www.freebsdwiki.net/index.php/Block_repeated_illegal_or_failed_SSH_logins</a></p>
<p style="text-align: center;">&nbsp;</p>
<p style="text-align: left;">First thing to do is setup some precautionary measures with sshd:</p>
<h2>Limiting SSH login sessions</h2>
<p>In your <a title="Sshd config" href="http://www.freebsdwiki.net/index.php/Sshd_config">sshd_config</a> file the following settings can also help slow down such attacks.</p>
<ul>
<li>LoginGraceTime</li>
</ul>
<dl>
<dd>
<dl>
<dd>The server disconnects after this time if the user has not successfully logged in. If the value is 0, there is no time limit. The default is 120 seconds.</dd>
</dl>
</dd>
</dl>
<ul>
<li>MaxStartups</li>
</ul>
<dl>
<dd>
<dl>
<dd>Specifies the maximum number of concurrent unauthenticated connections to the sshd daemon. Additional connections will be dropped until authentication succeeds or the LoginGraceTime expires for a connection. The default is 10. Alternatively, random early drop can be enabled by specifying the three colon separated values &#8220;start:rate:full&#8221; (e.g.,&#8221;10:30:60&#8243;). sshd will refuse connection attempts with a probability of &#8220;rate/100&#8243; (30%) if there are currently &#8220;start&#8221; (10) unauthenticated connections. The probability increases linearly and all connection attempts are refused if the number of unauthenticated connections reaches &#8220;full&#8221; </dd>
<dd> </dd>
<p>Next you want to make sure your log files are up to snuff and then setup a real basic script that scans those files(via a cron) and blocks IP&#8217;s based on the results.  I find IPFW invaluable for the work I do, so that&#8217;s the route I&#8217;m going but if you use PF or IPF there are instructions in the link above for them.</p>
<p><a id=".2Fetc.2Fsyslog.conf" name=".2Fetc.2Fsyslog.conf"></a></p>
<h3>/etc/syslog.conf</h3>
<p>You need an <em>auth.*</em> line in your <a title="Syslog.conf (page does not exist)" href="http://www.freebsdwiki.net/index.php?title=Syslog.conf&amp;action=edit&amp;redlink=1">syslog.conf</a> file in order to log all authentications.</p>
<pre>auth.*                                          /var/log/auth.log</pre>
<p><a id="Using_IPFW" name="Using_IPFW"></a></p>
<h3>Using IPFW</h3>
<p><a id="sshd-fwscan.sh" name="sshd-fwscan.sh"></a></p>
<h4>Create sshd-fwscan.sh and put it somewhere handy like /usr/local/sbin/</h4>
<pre>#!/bin/sh
if ipfw show | awk '{print $1}' | grep -q 20000 ; then
        ipfw delete 20000
fi
# This catches repeated attempts for both legal and illegal users
# No check for duplicate entries is performed, since the rule
# has been deleted.
awk '/sshd/ &amp;&amp; (/Invalid user/ || /authentication error/) {try[$(NF)]++}
END {for (h in try) if (try[h] &gt; 5) print h}' /var/log/auth.log |
while read ip
do
        ipfw -q add 20000 deny tcp from $ip to any in
done</pre>
<p><strong>Note:</strong> To make sure IP&#8217;s expire we delete and add rule <em>20000</em> of the firewall each time, thus if the IP&#8217;s are no longer <em>duplicates</em> in the auth.log they are no longer firewalled.</p>
<p>&nbsp;</p>
<p>That&#8217;s that, I just ran the script as a test and viola, I&#8217;ve got 3 new rules in IPFW blocking those IP&#8217;s.. hoorah! <img src='http://blog.netflowdevelopments.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
</dl>
</dd>
</dl>
]]></content:encoded>
			<wfw:commentRss>http://blog.netflowdevelopments.com/2011/08/01/automatically-blocking-brute-force-attacks-on-your-freebsd-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to do a global search and replace within a DB across all Tables</title>
		<link>http://blog.netflowdevelopments.com/2011/04/19/how-to-do-a-global-search-and-replace-within-a-db-across-all-tables/</link>
		<comments>http://blog.netflowdevelopments.com/2011/04/19/how-to-do-a-global-search-and-replace-within-a-db-across-all-tables/#comments</comments>
		<pubDate>Tue, 19 Apr 2011 18:11:36 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[all tables]]></category>
		<category><![CDATA[global]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[search replace]]></category>
		<guid isPermaLink="false">http://blog.netflowdevelopments.com/?p=650</guid>
		<description><![CDATA[As part of my take over the world campaign I&#8217;ve run into the need to automatically do a global Search and replace within a Mysql Database covering all tables.  For this you need a little php magic and luckily enough I found just that magic right here. I&#8217;ll save you the looking up time and [...]]]></description>
			<content:encoded><![CDATA[<p>As part of my take over the world campaign I&#8217;ve run into the need to automatically do a global Search and replace within a Mysql Database covering all tables.  For this you need a little php magic and luckily enough I found just that magic right <a title="Searcn and Replace in Mysql" href="http://www.mjdigital.co.uk/blog/search-and-replace-text-in-whole-mysql-database/" target="_blank">here</a>.</p>
<p>I&#8217;ll save you the looking up time and paste it below but make sure to thank to the original author on their blog:</p>
<p>&nbsp;</p>
<p><code> &lt;?php<br />
// Find and replace facility for complete MySQL database<br />
//<br />
// Written by Mark Jackson @ MJDIGITAL<br />
// Can be used by anyone - but give me a nod if you do!<br />
// http://www.mjdigital.co.uk/blog</p>
<p>// SEARCH FOR<br />
$search        = '**__FIND_THIS__**';</p>
<p>// REPLACE WITH<br />
$replace    = '**__REPLACE_WITH_THIS__**'; // (used if queryType below is set to 'replace')</p>
<p>// DB Details<br />
$hostname = "__DB_HOST__";<br />
$database = "__DB_DATABASE__";<br />
$username = "__DB_USER__";<br />
$password = "__DB_PASSWORD__";</p>
<p>// Query Type: 'search' or 'replace'<br />
$queryType = 'replace';</p>
<p>// show errors (.ini file dependant) - true/false<br />
$showErrors = true;</p>
<p>//////////////////////////////////////////////////////<br />
//<br />
//        DO NOT EDIT BELOW<br />
//<br />
//////////////////////////////////////////////////////</p>
<p>if($showErrors) {<br />
error_reporting(E_ALL);<br />
ini_set('error_reporting', E_ALL);<br />
ini_set('display_errors',1);<br />
}</p>
<p>// Create connectio to DB<br />
$MJCONN = mysql_pconnect($hostname, $username, $password) or trigger_error(mysql_error(),E_USER_ERROR);<br />
mysql_select_db($database,$MJCONN);</p>
<p>// Get list of tables<br />
$table_sql = 'SHOW TABLES';<br />
$table_q = mysql_query($table_sql,$MJCONN) or die("Cannot Query DB: ".mysql_error());<br />
$tables_r = mysql_fetch_assoc($table_q);<br />
$tables = array();</p>
<p>do{<br />
$tables[] = $tables_r['Tables_in_'.strtolower($database)];<br />
}while($tables_r = mysql_fetch_assoc($table_q));</p>
<p>// create array to hold required SQL<br />
$use_sql = array();</p>
<p>$rowHeading = ($queryType=='replace') ?<br />
'Replacing \''.$search.'\' with \''.$replace.'\' in \''.$database."'\n\nSTATUS    |    ROWS AFFECTED    |    TABLE/FIELD    (+ERROR)\n"<br />
: 'Searching for \''.$search.'\' in \''.$database."'\n\nSTATUS    |    ROWS CONTAINING    |    TABLE/FIELD    (+ERROR)\n";</p>
<p>$output = $rowHeading;</p>
<p>$summary = '';</p>
<p>// LOOP THROUGH EACH TABLE<br />
foreach($tables as $table) {<br />
// GET A LIST OF FIELDS<br />
$field_sql = 'SHOW FIELDS FROM '.$table;<br />
$field_q = mysql_query($field_sql,$MJCONN);<br />
$field_r = mysql_fetch_assoc($field_q);</p>
<p>// compile + run SQL<br />
do {<br />
$field = $field_r['Field'];<br />
$type = $field_r['Type'];</p>
<p>switch(true) {<br />
// set which column types can be replaced/searched<br />
case stristr(strtolower($type),'char'): $typeOK = true; break;<br />
case stristr(strtolower($type),'text'): $typeOK = true; break;<br />
case stristr(strtolower($type),'blob'): $typeOK = true; break;<br />
case stristr(strtolower($field_r['Key']),'pri'): $typeOK = false; break; // do not replace on primary keys<br />
default: $typeOK = false; break;<br />
}</p>
<p>if($typeOK) { // Field type is OK ro replacement<br />
// create unique handle for update_sql array<br />
$handle = $table.'_'.$field;<br />
if($queryType=='replace') {<br />
$sql[$handle]['sql'] = 'UPDATE '.$table.' SET '.$field.' = REPLACE('.$field.',\''.$search.'\',\''.$replace.'\')';<br />
} else {<br />
$sql[$handle]['sql'] = 'SELECT * FROM '.$table.' WHERE '.$field.' REGEXP(\''.$search.'\')';<br />
}</p>
<p>// execute SQL<br />
$error = false;<br />
$query = @mysql_query($sql[$handle]['sql'],$MJCONN) or $error = mysql_error();<br />
$row_count = @mysql_affected_rows() or $row_count = 0;</p>
<p>// store the output (just in case)<br />
$sql[$handle]['result'] = $query;<br />
$sql[$handle]['affected'] = $row_count;<br />
$sql[$handle]['error'] = $error;</p>
<p>// Write out Results into $output<br />
$output .= ($query) ? 'OK        ' : '--        ';<br />
$output .= ($row_count&gt;0) ? '&lt;strong&gt;'.$row_count.'&lt;/strong&gt;            ' : '&lt;span style="color:#CCC"&gt;'.$row_count.'&lt;/span&gt;            ';<br />
$fieldName = '`'.$table.'`.`'.$field.'`';<br />
$output .= $fieldName;<br />
$erTab = str_repeat(' ', (60-strlen($fieldName)) );<br />
$output .= ($error) ? $erTab.'(ERROR: '.$error.')' : '';</p>
<p>$output .= "\n";<br />
}<br />
}while($field_r = mysql_fetch_assoc($field_q));<br />
}</p>
<p>// write the output out to the page<br />
echo '&lt;pre&gt;';<br />
echo $output."\n";<br />
echo '&lt;pre&gt;';<br />
?&gt; </code></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.netflowdevelopments.com/2011/04/19/how-to-do-a-global-search-and-replace-within-a-db-across-all-tables/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creating a custom slideshow for your wallpaper in ubuntu</title>
		<link>http://blog.netflowdevelopments.com/2010/07/12/creating-a-custom-slideshow-for-your-wallpaper-in-ubuntu/</link>
		<comments>http://blog.netflowdevelopments.com/2010/07/12/creating-a-custom-slideshow-for-your-wallpaper-in-ubuntu/#comments</comments>
		<pubDate>Mon, 12 Jul 2010 10:21:13 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Linux / Freebsd]]></category>
		<category><![CDATA[add]]></category>
		<category><![CDATA[auto]]></category>
		<category><![CDATA[background]]></category>
		<category><![CDATA[cosmos]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[slideshow]]></category>
		<category><![CDATA[space art]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[wallpaper]]></category>
		<category><![CDATA[xml]]></category>
		<guid isPermaLink="false">http://blog.netflowdevelopments.com/?p=498</guid>
		<description><![CDATA[So it seems that I&#8217;ve had a similar experience to a lot of people changing their wallpapers in ubuntu.  You&#8217;re scrolling through a bunch and in the list you notice this one called cosmos that doesn&#8217;t quite looks like the rest.  &#8220;Hmmm, what&#8217;s this?&#8217; you think.  This looks like a bunch of images stacked on [...]]]></description>
			<content:encoded><![CDATA[<p>So it seems that I&#8217;ve had a similar experience to a lot of people changing their wallpapers in ubuntu.  You&#8217;re scrolling through a<img class="alignright" title="wallpaper" src="http://1.bp.blogspot.com/_njfTl4D4ZQU/Sz426eLDH8I/AAAAAAAAABI/OFixF5QPI9s/s320/sample1.png" alt="" width="320" height="270" /> bunch and in the list you notice this one called cosmos that doesn&#8217;t quite looks like the rest.  &#8220;Hmmm, what&#8217;s this?&#8217; you think.  This looks like a bunch of images stacked on top of each other.  Could it be?  And yes, it is, it&#8217;s a multi-image slideshow that can have as your background that rotates on a schedule that you choose.  I immediately sat down and started figuring out how this thing works and in the end it was pretty simple, time consuming to setup as you have to input a ton of values into an xml file but simple.  I&#8217;m not going to go into huge detail about how it works if you want to read more head over to <a href="http://www.linuxjournal.com/content/create-custom-transitioning-background-your-gnome-228-desktop" target="_blank">http://www.linuxjournal.com/content/create-custom-transitioning-background-your-gnome-228-desktop</a></p>
<p>So today I stumbled upon a motherload of amazing 3D space art at <a href="http://joejesus.deviantart.com">http://joejesus.deviantart.com</a> and I go completely gaga over space art.. My wallpapers are all sci-fi scenes, I just can&#8217;t get over how breath taking some of these are.  So I raided the guys stash and ended up with around 30-40 new pieces for my wallpaper slideshow and like hell was I going to enter all of these in by hand so off I went searching for a nice little script that would do it for me.  I mean come on, one of the reasons I&#8217;m a linux user because I gave up the notion that time consuming repetitive tasks were something that you had to do by hand and sure enough I found a wonderful gentlemen over at the ubuntu forums who coded up a beauty of a script that worked like a charm.  So make sure to head over to : <a href="http://ubuntuforums.org/showthread.php?p=9578962" target="_blank">http://ubuntuforums.org/showthread.php?p=9578962</a> and give the guy a big thank you hug for saving you hours of work, and read the instructions on how to use it.</p>
<p>Here&#8217;s the script, just copy and paste this into a file, chmod it to 755 and you&#8217;re off to the races:</p>
<blockquote>
<pre>#!/bin/sh
#This script creates xml files that can act as dynamic wallpapers for Gnome by referring to multiple wallpapers
#Coded by David J Krajnik
if [ "$*" = "" ]; then
  echo "This script creates xml files that can act as dynamic backgrounds for Gnome by referring to multiple wallpapers";
  echo "Usage: mkwlppr.sh target-file.xml [duration] pic1 pic2 [pic3 .. picN]";
else
  files=$*;
  #Grab the name of the target xml file
  xmlfile=`echo $files | cut -d " " -f 1`;
  #remove the first item from $files
  files=`echo $files | sed 's/^\&lt;[^ ]*\&gt;//'`;
  if [ "`echo $xmlfile | grep '\.xml$'`" = "" ]; then
    echo "Your target file must be an XML file";
  else
    inputIsValid="true";
    firstItem=`echo $files | cut -d " " -f 1`;
    duration="1795.0";#set the default duration
    if [ "`echo $firstItem | grep '^[0-9]\+\.[0-9]\+$'`" != "" ]; then
      echo "The duration must be an integer";
      files=`echo $files | sed 's/^\&lt;[^ ]*\&gt;//'`;
      inputIsValid="";
    elif [ "`echo $firstItem | grep '^[0-9]\+$'`" != "" ]; then
      #If the item is a number, then use it as the duration for each wallpaper image
      duration="`expr $firstItem - 5`.0";
      #remove the duration from the list of files
      files=`echo $files | sed 's/^\&lt;[^ ]*\&gt;//'`;
    fi
    if [ "$files" = "" ]; then
      echo "You must enter image files to associate with the XML file";
    else
      for file in $files
      do
        if [ ! -f $file ]; then
	  echo "\"$file\" does not exist";
	  inputIsValid="";
        elif [ "`echo $file | sed 's/^.*\.\(jpg\|jpeg\|bmp\|png\|gif\|tif\|tiff\|jif\|jfif\|jp2\|jpx\|j2k\|j2c\)$//'`" != "" ]; then
	  echo "\"$file\" is not an image file";
	  inputIsValid="";
	fi
      done
      if [ $inputIsValid ]; then
        currDir=`pwd`;
        echo "&lt;background&gt;" &gt;&gt; $xmlfile
        echo "  &lt;starttime&gt;\n    &lt;year&gt;2009&lt;/year&gt;\n    &lt;month&gt;08&lt;/month&gt;\n    &lt;day&gt;04&lt;/day&gt;" &gt;&gt; $xmlfile;
        echo "    &lt;hour&gt;00&lt;/hour&gt;\n    &lt;minute&gt;00&lt;/minute&gt;\n    &lt;second&gt;00&lt;/second&gt;\n  &lt;/starttime&gt;" &gt;&gt; $xmlfile;
        echo "  &lt;!-- This animation will start at midnight. --&gt;" &gt;&gt; $xmlfile;
        firstFile=`echo $files | cut -d " " -f 1`;#grab the first item
        if [ "`echo $firstFile | sed 's/\(.\).*/\1/'`" != "/" ]; then
          #If the first character in the filename is not '/', then it is a relative path and must have the current directory's path appended
          firstFile="$currDir/$firstFile";
        fi
        firstFile=`echo $firstFile | sed 's/[^/]\+\/\.\.\/\?//g'`;#Remove occurrences of ".." from the filepath
        files=`echo $files | sed 's/^\&lt;[^ ]*\&gt;//'`;#remove the first item
        prevFile=$firstFile;
        currFile="";
        #TODO add absolute path to the filenames
        #if $currFile =~ "^/.*" then the file needs to path appended
        echo "  &lt;static&gt;\n    &lt;duration&gt;$duration&lt;/duration&gt;\n    &lt;file&gt;$firstFile&lt;/file&gt;\n  &lt;/static&gt;" &gt;&gt; $xmlfile;
        for currFile in $files
        do
          if [ "`echo $currFile | sed 's/\(.\).*/\1/'`" != "/" ]; then
            #If the first character in the filename is not '/', then it is a relative path and must have the current directory's path appended
            currFile="$currDir/$currFile";
          fi
          currFile=`echo $currFile | sed 's/[^/]\+\/\.\.\/\?//g'`;#Remove occurrences of ".." from the filepath
          echo "  &lt;transition&gt;\n    &lt;duration&gt;5.0&lt;/duration&gt;\n    &lt;from&gt;$prevFile&lt;/from&gt;\n    &lt;to&gt;$currFile&lt;/to&gt;\n  &lt;/transition&gt;" &gt;&gt; $xmlfile;
          echo "  &lt;static&gt;\n    &lt;duration&gt;$duration&lt;/duration&gt;\n    &lt;file&gt;$currFile&lt;/file&gt;\n  &lt;/static&gt;" &gt;&gt; $xmlfile;
          prevFile=$currFile;
        done
        echo "  &lt;transition&gt;\n    &lt;duration&gt;5.0&lt;/duration&gt;\n    &lt;from&gt;$currFile&lt;/from&gt;\n    &lt;to&gt;$firstFile&lt;/to&gt;\n  &lt;/transition&gt;" &gt;&gt; $xmlfile;
        echo "&lt;/background&gt;" &gt;&gt; $xmlfile;
      fi
    fi
  fi
fi
</pre>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://blog.netflowdevelopments.com/2010/07/12/creating-a-custom-slideshow-for-your-wallpaper-in-ubuntu/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Your own free content spinner shell script in bash (fTW!)</title>
		<link>http://blog.netflowdevelopments.com/2010/04/18/your-own-free-content-spinner-shell-script-in-bash-ftw/</link>
		<comments>http://blog.netflowdevelopments.com/2010/04/18/your-own-free-content-spinner-shell-script-in-bash-ftw/#comments</comments>
		<pubDate>Mon, 19 Apr 2010 03:40:12 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[automate]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[content]]></category>
		<category><![CDATA[free]]></category>
		<category><![CDATA[generate]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[spinner]]></category>
		<guid isPermaLink="false">http://blog.netflowdevelopments.com/?p=436</guid>
		<description><![CDATA[So today I set out to modify my massive unique tweet and content generator for my Netsyphon network(ie: hotel-kelowna, innkelowna.com, kelownasrestaurants.com, etc etc) and add an inline content spinner to it.  To date there are a lot of search/replaces happening but they are all one time replaces and reference external files for the replace values..  [...]]]></description>
			<content:encoded><![CDATA[<p>So today I set out to  modify my massive unique tweet and content  generator for my Netsyphon  network(ie: <a href="http://hotel-kelowna.com" target="_blank">hotel-kelowna</a>,  <a href="http://innkelowna.com">innkelowna.com</a>,  <a href="http://kelownasrestaurants.com" target="_blank">kelownasrestaurants.com</a>, etc   etc) and add an inline content spinner to it.  To date there are a lot   of search/replaces happening but they are all one time replaces and   reference external files for the replace values..  Usually there were   only one or two possible s/r results per line so I could handle it   easily with gsub.</p>
<p>But now I wanted to be able to take a single  article with a ton of  spinnable content and have a script generate  10-20-100 different  versions of this article.  I would have a sentence  where 80% of the  content was spinnable with infinite amount of results.   I could handle  this with the old method but it would require creating a  ton of  external files for each search/replace possibility which would  get  insane.  Instead I knew that there had to be a relatively simple  method  with bash to make this happen, and much to my delight the boys  over at  #bash on irc.freenode came to the rescue</p>
<p>Big props out  to \amethyst and geirha, my two heroes for the day.   Some useful info  from #bash as well:</p>
<p>FAQ: <a href="http://mywiki.wooledge.org/BashFAQ">http://mywiki.wooledge.org/BashFAQ</a> | Guide: <a href="http://mywiki.wooledge.org/BashGuide">http://mywiki.wooledge.org/BashGuide</a> | ref: <a href="http://tinyurl.com/txlv">http://tinyurl.com/txlv</a> | <a href="http://bash-hackers.org/wiki/">http://bash-hackers.org/wiki/</a> | USE MORE QUOTES!: <a href="http://www.grymoire.com/Unix/Quote.html">http://www.grymoire.com/Unix/Quote.html</a> | Scripts and more: <a href="http://www.shelldorado.com/">http://www.shelldorado.com/</a></p>
<p>And without further ado here are the scripts that were created by these two gents.</p>
<p>http://pastebin.com/xNgKaR2c:</p>
<p><!-- p, li { white-space: pre-wrap; } -->FAQ: <a href="http://mywiki.wooledge.org/BashFAQ">http://mywiki.wooledge.org/BashFAQ</a> | Guide: <a href="http://mywiki.wooledge.org/BashGuide">http://mywiki.wooledge.org/BashGuide</a> | ref: <a href="http://tinyurl.com/txlv">http://tinyurl.com/txlv</a> | <a href="http://bash-hackers.org/wiki/">http://bash-hackers.org/wiki/</a> | USE MORE QUOTES!: <a href="http://www.grymoire.com/Unix/Quote.html">http://www.grymoire.com/Unix/Quote.html</a> | Scripts and more: <a href="http://www.shelldorado.com/">http://www.shelldorado.com/</a></p>
<p>And without further ado here are the  scripts that were created by these two gents.</p>
<p>The first by Geirha, is setup to read from an external file , and if not will take the input from stdin</p>
<p>http://pastebin.com/xNgKaR2c:</p>
<blockquote><p>spinner_thingy ()<br />
{<br />
while read -r -d &#8216;{&#8216;; do<br />
printf &#8220;%s&#8221; &#8220;$REPLY&#8221;;<br />
IFS=&#8217;|&#8217; read -r -d &#8216;}&#8217; -a words;<br />
n=${#words[@]};<br />
((n)) &amp;&amp; printf &#8220;%s&#8221; &#8220;${words[RANDOM%n]}&#8221;;<br />
done &lt; &#8220;${1:-/dev/stdin}&#8221;;<br />
printf &#8220;%s&#8221; &#8220;$REPLY&#8221;<br />
}</p></blockquote>
<p>The second by\amethyst can be found here: http://pastebin.com/tAXJ04L6</p>
<p>I went ahead and replaced the example line at the top with a reference to a filename</p>
<blockquote><p>line=&#8221;$(&lt;test.txt)&#8221;<br />
makesentence ()<br />
{<br />
local line=&#8221;$1&#8243;<br />
while [[ $line = *{*}* ]]; do<br />
local -a choices<br />
local prefix=${line%%{*} rest=${line#*{}<br />
local choice=${rest%%\}*}<br />
line=${rest#*\}}<br />
IFS=&#8217;|&#8217; read -a choices &lt;&lt;&lt; &#8220;$choice&#8221;<br />
[[ $choice = *"|" ]] &amp;&amp; choices+=( &#8220;&#8221; )<br />
printf &#8220;%s&#8221; &#8220;$prefix&#8221;<br />
if (( ${#choices[@]} )); then<br />
printf &#8220;%s&#8221; &#8220;${choices[RANDOM % ${#choices[@]}]}&#8221;<br />
fi<br />
done<br />
printf &#8220;%s\n&#8221; &#8220;$line&#8221;<br />
}<br />
makesentence &#8220;$line&#8221;</p></blockquote>
<p>So there you have it.. 30 minutes in IRC and the helpful boys over at #bash have me right as rain.. Again a big shout out, these guys have been integral in helping me with all of my scripting in this project.. I would have jack if it wasn&#8217;t for them.</p>
<p>As a parting gift I also found a way to do this with php, but alas I wanted a shell script that I could easily integrate into the mothership so it was all one nice neat package.. But for those php guys here it is:</p>
<blockquote><p><code>&lt;?php<br />
$text = "The {quick|slow|reasonably paced} {brown|green|blue|pink}  {fox|goat|rat|camel}<br />
{jumped|walked|hopped} {over|past|under} the {lazy|tired|boring}  {dog|cat|stoat}";<br />
$count = 0;<br />
while ($count++ &lt; 100){<br />
echo Spin($text);<br />
echo "&lt;br /&gt;";<br />
}<br />
?&gt;</code></p></blockquote>
<p>Now go generate some content!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.netflowdevelopments.com/2010/04/18/your-own-free-content-spinner-shell-script-in-bash-ftw/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

