<?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>osscc &#187; Bash Scripting</title>
	<atom:link href="http://www.osscc.org/category/documentation/tutorial/bash-scripting/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.osscc.org</link>
	<description>free open source software for cyber cafe</description>
	<lastBuildDate>Wed, 03 Aug 2011 18:06:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>More Fun With Bash Quoting</title>
		<link>http://www.osscc.org/2009/11/more-fun-with-bash-quoting/</link>
		<comments>http://www.osscc.org/2009/11/more-fun-with-bash-quoting/#comments</comments>
		<pubDate>Fri, 20 Nov 2009 06:39:00 +0000</pubDate>
		<dc:creator>osscc</dc:creator>
				<category><![CDATA[Bash Scripting]]></category>
		<category><![CDATA[Documentation]]></category>

		<guid isPermaLink="false">http://www.osscc.org/2009/11/more-fun-with-bash-quoting/</guid>
		<description><![CDATA[By Mitch Frazier Created 2009-11-19 11:52 &#160; I&#8217;ve written about bash quoting [1] before, and yes, it&#8217;s about as exciting as watching paint dry or listening to the corn grow. It can also be extremely frustrating when it doesn&#8217;t do what you want, case in point: trying to script the updating of a field in [...]]]></description>
			<content:encoded><![CDATA[<p>By <em>Mitch Frazier</em>
<div class="print-created">Created <em>2009-11-19 11:52</em></div>
<div class="print-created"><em>&nbsp;</em></div>
<p>
<div class="print-content">I&#8217;ve written about <a class="reference" href="http://www.linuxjournal.com/content/bash-quoting">bash quoting</a> <span class="print-footnote">[1]</span> before, and yes, it&#8217;s about as exciting as watching paint dry or listening to the corn grow. It can also be extremely frustrating when it doesn&#8217;t do what you want, case in point: trying to script the updating of a field in a mysql table when the field to be changed contains quote characters.<br />Let&#8217;s imagine we have a simple table with the following data and we would like to change the name field:
<div class="highlight">
<pre>+----+----------------------+---------------------+| id | name                 | create_date         |+----+----------------------+---------------------+|  1 | name 'with' "quotes" | 2009-11-19 08:48:59 |+----+----------------------+---------------------+</pre>
</div>
<p>Your first script might look something like this:
<div class="highlight">
<pre><span class="c">#!/bin/bash</span>

<span class="nv">USERNAME</span><span class="o">=</span><span class="k">${</span><span class="nv">USERNAME</span><span class="k">:-</span><span class="nv">user</span><span class="k">}</span><span class="nv">PASSWORD</span><span class="o">=</span><span class="k">${</span><span class="nv">PASSWORD</span><span class="k">:-</span><span class="nv">pwd</span><span class="k">}</span>

<span class="nv">mysql_cmd</span><span class="o">=</span><span class="s2">"mysql -u $USERNAME -p$PASSWORD test"</span>

<span class="c"># Remove mysql header line.</span><span class="k">function </span>remove_header<span class="o">()</span><span class="o">{</span>    <span class="nb">shift</span><span class="nb">    echo</span> <span class="nv">$*</span><span class="o">}</span>

<span class="nv">id</span><span class="o">=</span>1<span class="nv">name</span><span class="o">=</span><span class="k">$(</span>remove_header <span class="k">$(</span><span class="nv">$mysql_cmd</span> -e <span class="s2">"SELECT name FROM atable WHERE id='$id'"</span><span class="k">))</span>

<span class="nv">new_name</span><span class="o">=</span><span class="s2">"$name and more"</span><span class="nb">echo </span>mysql -e <span class="s2">"UPDATE atable SET name='$new_name' WHERE id='$id'"</span><span class="nv">$mysql_cmd</span> -e <span class="s2">"UPDATE atable SET name='$new_name' WHERE id='$id'"</span>

<span class="c"># vim: tabstop=4: shiftwidth=4: noexpandtab:</span><span class="c"># kate: tab-width 4; indent-width 4; replace-tabs false;</span></pre>
</div>
<p>And when you run it, it will puke something like this:
<div class="highlight">
<pre><span class="nv">$ </span>bash badfix.shmysql -e UPDATE atable SET <span class="nv">name</span><span class="o">=</span><span class="s1">'name '</span>with<span class="s1">' quotes and more'</span> WHERE <span class="nv">id</span><span class="o">=</span><span class="s1">'1'</span>ERROR 1064 <span class="o">(</span>42000<span class="o">)</span> at line 1:    You have an error in your SQL syntax;    check the manual that corresponds to your MySQL server version    <span class="k">for </span>the right syntax to use near <span class="s1">'with'</span> quotes and more<span class="s1">' WHERE id='</span>1<span class="s1">''</span>    at line 1</pre>
</div>
<p>Note, the function at the top (<tt class="docutils literal"><span class="pre">remove_header</span></tt>) removes the header line from the mysql output so that we don&#8217;t get the name of the field included in the data.<br />We all know the solution here: we need to escape the quotes in the value so that both bash and mysql are happy. However, this turns out to be easier said than done, and perhaps I missed the obvious, but after numerous attempts (on more than one occasion) the following finally did the trick:
<div class="highlight">
<pre><span class="c">#!/bin/bash</span>

<span class="nv">USERNAME</span><span class="o">=</span><span class="k">${</span><span class="nv">USERNAME</span><span class="k">:-</span><span class="nv">user</span><span class="k">}</span><span class="nv">PASSWORD</span><span class="o">=</span><span class="k">${</span><span class="nv">PASSWORD</span><span class="k">:-</span><span class="nv">pwd</span><span class="k">}</span>

<span class="nv">mysql_cmd</span><span class="o">=</span><span class="s2">"mysql -u $USERNAME -p$PASSWORD test"</span>

<span class="c"># Remove mysql header line.</span><span class="k">function </span>remove_header<span class="o">()</span><span class="o">{</span>    <span class="nb">shift</span><span class="nb">    echo</span> <span class="nv">$*</span><span class="o">}</span>

<span class="c"># Quote any quotes in a mysql value.</span><span class="k">function </span>fix_quotes<span class="o">()</span><span class="o">{</span>    <span class="nb">local  </span><span class="nv">val</span><span class="o">=</span><span class="s2">"$*"</span>    <span class="k">if</span> <span class="o">[[</span> <span class="s2">"$val"</span> <span class="o">=</span>~ .*<span class="se">\'</span>.* <span class="o">]]</span>; <span class="k">then</span> <span class="c">#'</span>        <span class="nb">echo</span> <span class="s2">"String contains single quotes: $val"</span> &gt;&amp;2        <span class="c">#val="${val//'/\\\\'}"</span>        <span class="nv">val</span><span class="o">=</span><span class="k">$(</span>sed -e <span class="s2">"s/'/' \"'\" '/g"</span> &lt;&lt;&lt;<span class="s2">"$val"</span><span class="k">)</span>        <span class="nb">echo </span>New Value: <span class="s2">"$val"</span> &gt;&amp;2    <span class="k">fi</span><span class="k">    </span><span class="nb">echo</span> <span class="s2">"$val"</span><span class="o">}</span>

<span class="nv">id</span><span class="o">=</span>1<span class="nv">name</span><span class="o">=</span><span class="k">$(</span>remove_header <span class="k">$(</span><span class="nv">$mysql_cmd</span> -e <span class="s2">"SELECT name FROM atable WHERE id='$id'"</span><span class="k">))</span>

<span class="nv">fixed_name</span><span class="o">=</span><span class="s2">"$(fix_quotes "</span><span class="nv">$name</span><span class="s2">") and more"</span><span class="nb">echo </span>mysql -e <span class="s2">"UPDATE atable SET name='$fixed_name' WHERE id='$id'"</span><span class="nv">$mysql_cmd</span> -e <span class="s2">"UPDATE atable SET name='$fixed_name' WHERE id='$id'"</span>

<span class="c"># vim: tabstop=4: shiftwidth=4: noexpandtab:</span><span class="c"># kate: tab-width 4; indent-width 4; replace-tabs false;</span></pre>
</div>
<p>The <tt class="docutils literal"><span class="pre">fix_quotes</span></tt> function only checks for single quotes since our mysql value is contained in single quotes:
<div class="highlight">
<pre><span class="nv">$mysql_cmd</span> -e <span class="s2">"UPDATE atable SET name='$fixed_name' WHERE id='$id'"</span><span class="c">#                                     ^           ^</span></pre>
</div>
<p>As you would expect, we don&#8217;t need to escape double quotes inside single quotes for mysql. However, if we wanted to use a literal value in our SQL command we would need to escape double quotes since our SQL command is contained inside double quotes:
<div class="highlight">
<pre><span class="nv">$mysql_cmd</span> -e <span class="s2">"UPDATE atable SET name='quoted \"value\"' WHERE id='$id'"</span><span class="c">#             ^                                                        ^</span></pre>
</div>
<p>We need to escape them in this case for bash&#8217;s benefit and not for mysql: bash will &#8220;remove&#8221; the backslashes before passing the command to mysql.<br />One of my initial attempts (which you can see commented out in the code) was to try to change the value directly using a bash assignment statement. I tried to change each single quote to an escaped single quote:
<div class="highlight">
<pre><span class="nv">val</span><span class="o">=</span><span class="s2">"${val//'/\\\\'}"</span></pre>
</div>
<p>Interestingly, this does not modify the string at all, a result that I don&#8217;t quite understand. I tried a similar thing using <tt class="docutils literal"><span class="pre">sed</span></tt> and that also did not work. The solution that finally worked is based on the fact that mysql, like C++, concatenates adjacent strings into a single string. So, I change (using <tt class="docutils literal"><span class="pre">sed</span></tt>) all single quotes inside the string into the sequence: single-quote, space, double-quote, single-quote, double-quote, space, single-quote.  You may notice that the double quotes are escaped, but that&#8217;s for escaping within the <tt class="docutils literal"><span class="pre">sed</span></tt> command, those don&#8217;t make it into the value that&#8217;s passed to mysql.
<div class="highlight">
<pre><span class="nv">val</span><span class="o">=</span><span class="k">$(</span>sed -e <span class="s2">"s/'/' \"'\" '/g"</span> &lt;&lt;&lt;<span class="s2">"$val"</span><span class="k">)</span></pre>
</div>
<p>Running this final version does the trick:
<div class="highlight">
<pre><span class="nv">$ </span>bash fix.shString contains single quotes: name <span class="s1">'with'</span> <span class="se">\"</span>quotes<span class="se">\"</span>New Value: name <span class="s1">' "'</span><span class="s2">" 'with' "</span><span class="s1">'" '</span> <span class="se">\"</span>quotes<span class="se">\"</span>mysql -e UPDATE atable SET <span class="nv">name</span><span class="o">=</span><span class="s1">'name '</span> <span class="s2">"'"</span> <span class="s1">'with'</span> <span class="s2">"'"</span> <span class="s1">' \"quotes\" and more'</span> WHERE <span class="nv">id</span><span class="o">=</span><span class="s1">'1'</span></pre>
</div>
<p>and you can see the result in the table.
<div class="highlight">
<pre>+----+-------------------------------+---------------------+| id | name                          | create_date         |+----+-------------------------------+---------------------+|  1 | name 'with' "quotes" and more | 2009-11-19 08:48:59 |+----+-------------------------------+---------------------+</pre>
</div>
<p>Have we had enough quoting yet????<br />__________________________ <br />Mitch Frazier is an Associate Editor for <i>Linux Journal</i> and the Web Editor for linuxjournal.com.</div>
<div class="print-footer"> </div>
<hr class="print-hr" />
<div class="print-source_url"><strong>Source URL:</strong> <a href="http://www.linuxjournal.com/content/more-fun-bash-quoting">http://www.linuxjournal.com/content/more-fun-bash-quoting</a></div>
<p><strong>Links:</strong><br />[1] http://www.linuxjournal.com/content/bash-quoting</p>
<p><map name='google_ad_map_159_3db9945d9ae1c815'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/159?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_159_3db9945d9ae1c815' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=159&amp;url= http%3A%2F%2Fwww.osscc.org%2F2009%2F11%2Fmore-fun-with-bash-quoting%2F' /></p>]]></content:encoded>
			<wfw:commentRss>http://www.osscc.org/2009/11/more-fun-with-bash-quoting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

