<h2 id="bash-and-quoted-strings">Bash and quoted strings</h2>
<p>An issue I just hit in Bash was that I had a quoted string, and I wanted to enclose it in quotes. How to do this?</p>
<p>This is the umpteenth time I have stumbled over this issue, and I realised I had found out how to solve it a while back but the information hadn’t rooted itself into my mind!</p>
<p>I have always been less clear in my mind about quoted strings in Bash than I should be, so, assuming others might have similar confusion I thought I’d try and clarify things in the form of an HPR show.</p>
<h3 id="the-problem">The problem</h3>
<p>The thing I was having difficulties with was an <code>alias</code> definition of a useful pipeline:</p>
<pre><code>nmap -sn 192.168.0.0/24 | awk &#39;/^Nmap scan report/{print &quot;&quot;; print; next}{print}&#39;</code></pre>
<p>This uses <code>nmap</code> (see Ken’s show <a href="https://hackerpublicradio.org/eps.php?id=3052" title="hpr3052 :: Locating computers on a network">3052</a> for a discussion of its use) piped into an <code>awk</code> one-liner that formats the information returned by <code>nmap</code>.</p>
<p>The <code>alias</code> command can be used to store such a command or command sequence as a single simple command. It’s usually added to the <code>~/.bashrc</code> file so it gets added to every Bash shell you start up (note <em>Bash Tips #22</em>, currently being written, will cover these startup files).</p>
<p>An <code>alias</code> definition looks something like this:</p>
<pre><code>alias la=&#39;ls -Al&#39;</code></pre>
<p>The alias itself <code>'la'</code> is defined as the command <code>ls -Al</code>.</p>
<p>So how to make my <code>nmap</code> sequence into an alias given that the commands contain both single and double quotes?</p>
<h3 id="quoted-strings-in-bash">Quoted strings in Bash</h3>
<p>Bash is (to my mind) a bit weird with quoted strings.</p>
<p>There are two sorts of quotes in Bash (leaving aside the <em>backquote</em> or <em>backtick</em> – <code>`</code>):</p>
<ul>
<li><p>Single quotes, also called <em>hard</em> quotes (<code>'</code>). The literal value of characters between the quotes is preserved. Single quotes are not allowed, even if preceded by backslash escape characters.</p></li>
<li><p>Double quotes, also called <em>soft</em> quotes (<code>"</code>). Certain characters within the quotes have special meanings, such as <code>'$'</code> and <code>'&bsol;'</code>. Double quotes are allowed in the string when preceded by a backslash.</p></li>
</ul>
<p>There’s a more comprehensive treatment of these quoting types (and others) in the <a href="https://www.gnu.org/software/bash/manual/html_node/Quoting.html" title="Bash Reference Manual: 3.1.2 Quoting">Bash Reference Manual</a>.</p>
<h3 id="changing-quotes-and-concatenating-strings">Changing quotes and concatenating strings</h3>
<p>To make a variable containing a string with embedded quotes you can do this:</p>
<pre><code>$ x=&#39;string1&#39;&quot;&#39;&quot;&#39;string2&#39;
$ echo $x
string1&#39;string2</code></pre>
<p>What we did here was close <code>'string1'</code>, start a new string enclosed in double quotes <code>"'"</code>, then append a second string <code>'string2'</code>. Bash treats the three strings as one, but they have to be contiguous. There must be no intervening spaces<a href="#fn1" class="footnote-ref" id="fnref1"><sup>1</sup></a>.</p>
<p>This solution is rather ugly. You could also use Bash string concatenation to do this, though it’s more long-winded:</p>
<pre><code>$ x=&#39;string1&#39;
$ x+=&quot;&#39;&quot;
$ x+=&#39;string2&#39;
$ echo $x
string1&#39;string2</code></pre>
<p>The same principles hold for double quotes of course:</p>
<pre><code>$ x=&quot;string1&quot;&#39;&quot;&#39;&quot;string2&quot;
$ echo $x
string1&quot;string2</code></pre>
<p>You’d probably not want to do this though.</p>
<h3 id="using-backslashes">Using backslashes</h3>
<p>You can use backslashes to escape double quotes inside a <em>double</em> quoted string in Bash as we have seen.</p>
<pre><code>$ x=&quot;string1&bsol;&quot;string2&quot;
$ echo $x
string1&quot;string2</code></pre>
<p>However, as discussed earlier, it’s not possible to use backslashes to escape single quotes inside a single quoted string in Bash. However, outside a string a backslashed character is <em>escaped</em>. For example, if you have files which have spaces in their names, you can quote the name or use the backslash escape to protect the spaces<a href="#fn2" class="footnote-ref" id="fnref2"><sup>2</sup></a>:</p>
<pre><code>$ ls -l a&bsol; file&bsol; with&bsol; spaces.awk
-rw-r--r-- 1 hprdemo hprdemo 0 Apr 22 22:25 &#39;a file with spaces.awk&#39;</code></pre>
<p>So, knowing this, you can exit a string, concatenate with a backslashed quote then restart a string like this:</p>
<pre><code>$ x=&#39;string1&#39;&bsol;&#39;&#39;string2&#39;
$ echo $x
string1&#39;string2</code></pre>
<h3 id="solution">Solution</h3>
<p>So now we can see how to achieve the alias definition I wanted earlier:</p>
<pre><code>alias show_network=&#39;nmap -sn 192.168.0.0/24 | awk &#39;&bsol;&#39;&#39;/^Nmap scan report/{print &quot;&quot;; print; next}{print}&#39;&bsol;&#39;&#39;&#39;

</code></pre>
<h3 id="epilogue">Epilogue</h3>
<p>There’s more to be said about this subject, but too much of this stuff is not healthy.</p>
<h2 id="links">Links</h2>
<ul>
<li><p>Ken Fallon’s HPR show where he describes <code>nmap</code>: <a href="https://hackerpublicradio.org/eps.php?id=3052">hpr3052 :: Locating computers on a network</a></p></li>
<li>Bash Reference Manual:
<ul>
<li><a href="https://www.gnu.org/software/bash/manual/html_node/Quoting.html">Quoting</a></li>
</ul></li>
<li>Stack Overflow articles:
<ul>
<li><a href="https://stackoverflow.com/questions/6697753/difference-between-single-and-double-quotes-in-bash">Difference between single and double quotes in Bash</a></li>
<li><a href="https://stackoverflow.com/questions/3834839/how-to-escape-a-double-quote-inside-double-quotes">How to escape a double quote inside double quotes</a></li>
</ul></li>
</ul>
<section class="footnotes">
<hr />
<ol>
<li id="fn1"><p>This is quite an artificial example to make a point. You wouldn’t do things this way in reality. Using <code>x='string1'"'string2"</code> would also work (<code>'string1'</code> in single quotes, and <code>"'string2'"</code> in double quotes). Also, you could just write <code>x="string1'string2"</code> and stop all the messing about, but that would not be much of an example!<a href="#fnref1" class="footnote-back">↩</a></p></li>
<li id="fn2"><p>The backslash is making the space a literal space, otherwise Bash would see it as an argument delimiter, and would look for the files <code>'a'</code>, <code>'file'</code>, <code>'with'</code> and <code>'spaces.awk'</code> to list details about!<a href="#fnref2" class="footnote-back">↩</a></p></li>
</ol>
</section>
