Move under www to ease rsync
This commit is contained in:
196
www/eps/hpr2639/hpr2639_full_shownotes.html
Executable file
196
www/eps/hpr2639/hpr2639_full_shownotes.html
Executable file
@@ -0,0 +1,196 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="generator" content="pandoc">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<meta name="author" content="Dave Morriss">
|
||||
<title>Some ancillary Bash tips - 9 (HPR Show 2639)</title>
|
||||
<style type="text/css">code{white-space: pre;}</style>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link rel="stylesheet" href="http://hackerpublicradio.org/css/hpr.css">
|
||||
</head>
|
||||
|
||||
<body id="home">
|
||||
<div id="container" class="shadow">
|
||||
<header>
|
||||
<h1 class="title">Some ancillary Bash tips - 9 (HPR Show 2639)</h1>
|
||||
<h2 class="author">Dave Morriss</h2>
|
||||
<hr/>
|
||||
</header>
|
||||
|
||||
<main id="maincontent">
|
||||
<article>
|
||||
<header>
|
||||
<h1>Table of Contents</h1>
|
||||
<nav id="TOC">
|
||||
<ul>
|
||||
<li><a href="#making-decisions-in-bash">Making decisions in Bash</a></li>
|
||||
<li><a href="#types-of-test">Types of test</a><ul>
|
||||
<li><a href="#the-and-operators-and-the-test-command">The <code>'['</code> and <code>']'</code> operators and the <code>test</code> command</a></li>
|
||||
<li><a href="#shell-arithmetic">Shell arithmetic</a></li>
|
||||
<li><a href="#the-and-operators">The <code>'[['</code> and <code>']]'</code> operators</a></li>
|
||||
<li><a href="#bash-functions-commands-and-programs">Bash functions, commands and programs</a></li>
|
||||
<li><a href="#understanding-the-status-of-a-command">Understanding the status of a command</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#links">Links</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<h2 id="making-decisions-in-bash">Making decisions in Bash</h2>
|
||||
<p>This is my ninth contribution to the <a href="http://hackerpublicradio.org/series.php?id=42" title="*Bash Scripting* series"><em>Bash Scripting</em></a> series under the heading of <em>Bash Tips</em>. The previous episodes are listed below in the <a href="#links">Links</a> section.</p>
|
||||
<p>It seems to me that it would be worthwhile looking at how Bash can be used to make decisions, such as how many times a loop should cycle (<em>looping constructs</em>) or to choose between multiple choices (<em>conditional constructs</em>). Of course we need to look at some of the expressions used in conjunction with the commands that do these tasks – the tests themselves – and we’ll do this in this episode.</p>
|
||||
<p>This is a complex area which I had some trouble with when I first started using Bash, and there is a lot to say about it all. I have prepared a group of HPR shows about this subject, in order to do it justice, and this is the first of the group.</p>
|
||||
<h2 id="types-of-test">Types of test</h2>
|
||||
<p>There are four main types of test that can be used to make decisions in Bash:</p>
|
||||
<ul>
|
||||
<li>expressions with the <code>test</code> command and the <code>'['</code> and <code>']'</code> operators</li>
|
||||
<li>shell arithmetic</li>
|
||||
<li>expressions with the <code>'[['</code> and <code>']]'</code> operators</li>
|
||||
<li>Bash functions, commands and programs (in certain contexts)</li>
|
||||
</ul>
|
||||
<p>Note that in some examples in this episode we are using commands which haven’t been properly explained yet, but we will be covering them later in this group of shows.</p>
|
||||
<h3 id="the-and-operators-and-the-test-command">The <code>'['</code> and <code>']'</code> operators and the <code>test</code> command</h3>
|
||||
<p>Using <code>'[</code> <em>expression</em> <code>]'</code> or <code>'test</code> <em>expression</em><code>'</code> is the same (except that in the former case both square brackets are required). These are built-in commands inherited by Bash from its predecessor the <em>Bourne Shell</em>. See the <a href="https://www.gnu.org/software/bash/manual/bash.html#Bourne-Shell-Builtins" title="Bourne Shell Builtins">GNU Manual section on <em>builtins</em></a> for all of the details. The single square brackets and the <code>test</code> command are standard across other shells that confirm to the POSIX standard, so it is important to know about them.</p>
|
||||
<p>Note that since <code>'['</code> and <code>']'</code> are considered to be equivalent to commands they must be separated from their arguments by at least one space. It is a common error for Bash beginners to write something like:</p>
|
||||
<pre><code>if [$i -gt 0]; then
|
||||
echo "Positive"
|
||||
fi</code></pre>
|
||||
<p>This results in an error such as:</p>
|
||||
<pre><code>bash: [2: command not found</code></pre>
|
||||
<p>This is because the left square bracket and the value of variable <code>'i'</code> have been concatenated since there is no intervening space.</p>
|
||||
<p>The <em>expression</em> between square brackets (or following <code>test</code>) is a <em>Conditional Expression</em>, which is well documented in the <a href="https://www.gnu.org/software/bash/manual/bash.html#Bash-Conditional-Expressions" title="Bash Conditional Expressions">GNU Bash Manual section</a>. We will be looking these later in this group of shows.</p>
|
||||
<h3 id="shell-arithmetic">Shell arithmetic</h3>
|
||||
<p>We looked at some aspects of this subject in <a href="http://hackerpublicradio.org/eps/hpr1951" title="Some additional Bash tips">show 1951</a>. This show covered <em>arithmetic expansion</em> and mentioned the <a href="https://www.gnu.org/software/bash/manual/bash.html#Shell-Arithmetic" title="Bash Shell Arithmetic">arithmetic expressions</a> available in Bash. The type of arithmetic expansion expression we looked at was:</p>
|
||||
<pre><code>$ echo $((42/5))
|
||||
8</code></pre>
|
||||
<p>There is also a form consisting of:</p>
|
||||
<pre><code>(( expression ))</code></pre>
|
||||
<p>Note that Bash does not care whether you use spaces before and after the <em>expression</em>.</p>
|
||||
<p>It is possible to assign values and to compare them in this expression. When being used as a test expression the numeric result is used to obtain a <em>true</em>/<em>false</em> value:</p>
|
||||
<ul>
|
||||
<li>if the value of the expression is non-zero, the return status is 0 (<em>true</em>)</li>
|
||||
<li>otherwise the return status is 1 (<em>false</em>)</li>
|
||||
</ul>
|
||||
<p>The following downloadable example (<a href="hpr2639_bash9_ex1.sh">bash9_ex1.sh</a>) demonstrates how this type of test behaves:</p>
|
||||
<pre><code>$ cat bash9_ex1.sh
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Demonstration of the arithmetic expressions as tests
|
||||
#
|
||||
|
||||
for i in {-3..3}; do
|
||||
echo -n "$i: "
|
||||
if ((i)); then
|
||||
echo "$? true"
|
||||
else
|
||||
echo "$? false"
|
||||
fi
|
||||
done
|
||||
|
||||
exit
|
||||
$ ./bash9_ex1.sh
|
||||
-3: 0 true
|
||||
-2: 0 true
|
||||
-1: 0 true
|
||||
0: 1 false
|
||||
1: 0 true
|
||||
2: 0 true
|
||||
3: 0 true</code></pre>
|
||||
<p>All values except for zero return a result of 0 (<em>true</em>).</p>
|
||||
<p>The <em>expression</em> in the double parentheses can be a numeric assignment:</p>
|
||||
<pre><code>((x = 42))</code></pre>
|
||||
<p>This would be regarded as <em>true</em> in a test since 42 is non-zero.</p>
|
||||
<p>The <em>expression</em> may also be a comparison:</p>
|
||||
<pre><code>((x == 42))</code></pre>
|
||||
<p>This expression will have a non-zero value and will return the result zero (<em>true</em>), so in a test it can be used to check the value of an integer variable.</p>
|
||||
<p>There are also Boolean (logical) operators such as <code>&&</code> (and) and <code>||</code> so it is possible to write an expression such as:</p>
|
||||
<pre><code>((x == 42 && y != 42))</code></pre>
|
||||
<p>This will be <em>true</em> when <code>x</code> is 42 and <code>y</code> is not.</p>
|
||||
<p>The <a href="https://www.gnu.org/software/bash/manual/bash.html#Shell-Arithmetic" title="Bash Shell Arithmetic">arithmetic expressions</a> section of the GNU Bash Manual lists all of the arithmetic operators available in Bash.</p>
|
||||
<h3 id="the-and-operators">The <code>'[['</code> and <code>']]'</code> operators</h3>
|
||||
<p>We have seen the use of single square brackets (and the <code>test</code> command), but Bash offers an alternative using double square brackets as in:</p>
|
||||
<pre><code>[[ expression ]]</code></pre>
|
||||
<p>This form, often referred to as the <em>extended test</em>, also returns a status of zero or 1 after evaluating the conditional expression <em>expression</em>. The possible conditional expressions are documented in the <a href="https://www.gnu.org/software/bash/manual/bash.html#Bash-Conditional-Expressions" title="Bash Conditional Expressions">GNU Bash Manual</a>, and we will look at these later.</p>
|
||||
<p>Just as with the single left square bracket the double bracket is a command (actually it’s a <em>keyword</em> but the way it’s used is the same), so it must be followed by a space. Spaces are also required before the closing bracket or brackets.</p>
|
||||
<p>One of the differences between <code>[ expression ]</code> and <code>[[ expression ]]</code> is that with the former you should enclose the left operand in double quotes, as in:</p>
|
||||
<pre><code>[ "$n" -eq 42 ]</code></pre>
|
||||
<p>The reason is that if variable <code>n</code> is null or empty and there are no quotes the expression will become:</p>
|
||||
<pre><code>[ -eq 42 ]</code></pre>
|
||||
<p>This is illegal.</p>
|
||||
<p>However, with the double bracket form omitting the quotes is accepted:</p>
|
||||
<pre><code>[[ $n -eq 42 ]]</code></pre>
|
||||
<p>The way in which the contents of these double brackets are processed by Bash is different; to quote the GNU Bash manual:</p>
|
||||
<blockquote>
|
||||
<p>Word splitting and filename expansion are not performed on the words between the <code>'[['</code> and <code>']]'</code>; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed.</p>
|
||||
</blockquote>
|
||||
<p>We covered nearly all of these expansion topics in earlier episodes of <em>Bash Tips</em>.</p>
|
||||
<h3 id="bash-functions-commands-and-programs">Bash functions, commands and programs</h3>
|
||||
<p>So far I have not done any episodes describing how to write Bash functions, though there have been several more advanced episodes talking about some useful functions I have written for use in scripts. Functions are able to return status values, and such functions can be used as test commands to control some of the commands mentioned. See the <code>yes_no</code> function discussed in <a href="http://hackerpublicradio.org/eps/hpr2096" title="Useful Bash functions - part 2">episode 2096</a> for an example that can be used in tests.</p>
|
||||
<p>Commands like <code>grep</code> can be used in a test:</p>
|
||||
<pre><code>if grep -q -e '^banana$' fruit.txt; then
|
||||
echo "Found a banana"
|
||||
fi</code></pre>
|
||||
<p>Here the <code>-q</code> option prevents <code>grep</code> from reporting anything, it just returns a status. The string ‘banana’ is being searched for in the file <code>fruit.txt</code>. If found then <code>grep</code> will exit with a zero status, in other words, a <em>true</em> value and this will then cause the <code>if</code> command to execute the <code>echo</code> command.</p>
|
||||
<p>It is also possible to run a script or compiled program (possibly one that you have written) in the same way. This relies on the script or program returning a status that signifies success or failure. Most installed tools do this, as we saw with <code>grep</code>.</p>
|
||||
<p>Bash itself provides two commands <code>true</code> and <code>false</code> which may be programs (perhaps <code>/bin/true</code> and <code>/bin/false</code>) or, more likely, built-in commands, depending on the operating system version you are using. In my case I find that both exist:</p>
|
||||
<pre><code>$ which true false
|
||||
/bin/true
|
||||
/bin/false
|
||||
$ type true false
|
||||
true is a shell builtin
|
||||
false is a shell builtin</code></pre>
|
||||
<p>The <code>which</code> command finds programs and the <code>type</code> command reports what type of thing a command is.</p>
|
||||
<p>The <code>true</code> and <code>false</code> commands return <em>true</em> and <em>false</em> status values, in the way explained below. The builtin version will normally be the preferred one.</p>
|
||||
<p>In the next episode on Looping Constructs and Conditional Constructs the components marked <em>test_commands</em> used in the syntax descriptions are expressions that return a status of 0 (<em>true</em>) or non-zero (<em>false</em>) in the way just explained.</p>
|
||||
<h3 id="understanding-the-status-of-a-command">Understanding the status of a command</h3>
|
||||
<p>It is important to understand the concept of the return <u>status</u> of a command. The command:</p>
|
||||
<pre><code>$ echo "99"</code></pre>
|
||||
<p>displays the number 99 but returns a status of zero, which denotes the value <em>true</em>. This status is held in the special Bash variable <code>$?</code> which can be tested or displayed. Note that, <b>every</b> command resets the status, so the original value is easily lost:</p>
|
||||
<pre><code>$ echo "99"
|
||||
99
|
||||
$ echo $?
|
||||
0</code></pre>
|
||||
<p>If the command fails then a <em>false</em> (non-zero) value will returned:</p>
|
||||
<pre><code>$ echo (
|
||||
bash: syntax error near unexpected token `newline'
|
||||
$ echo $?
|
||||
2</code></pre>
|
||||
<p>Here we see that the <code>false</code> command generates a status of 1 (<em>false</em>) but the act of looking at <code>$?</code> changes its previous contents:</p>
|
||||
<pre><code>$ false
|
||||
$ echo $?
|
||||
1
|
||||
$ echo $?
|
||||
0</code></pre>
|
||||
<h2 id="links">Links</h2>
|
||||
<ul>
|
||||
<li><a href="https://www.gnu.org/software/bash/manual/bash.html">“<em>GNU BASH Reference Manual</em>”</a>
|
||||
<ul>
|
||||
<li><a href="https://www.gnu.org/software/bash/manual/bash.html#Bash-Conditional-Expressions">“Bash Conditional Expressions”</a></li>
|
||||
<li><a href="https://www.gnu.org/software/bash/manual/bash.html#Bourne-Shell-Builtins">“Bourne Shell Builtins”</a></li>
|
||||
</ul></li>
|
||||
<li><a href="http://hackerpublicradio.org/series.php?id=42">HPR series: <em>Bash Scripting</em></a></li>
|
||||
<li>Previous episodes under the heading <em>Bash Tips</em>:
|
||||
<ol>
|
||||
<li><a href="http://hackerpublicradio.org/eps/hpr1648">HPR episode 1648 “<em>Bash parameter manipulation</em>”</a></li>
|
||||
<li><a href="http://hackerpublicradio.org/eps/hpr1843">HPR episode 1843 “<em>Some Bash tips</em>”</a></li>
|
||||
<li><a href="http://hackerpublicradio.org/eps/hpr1884">HPR episode 1884 “<em>Some more Bash tips</em>”</a></li>
|
||||
<li><a href="http://hackerpublicradio.org/eps/hpr1903">HPR episode 1903 “<em>Some further Bash tips</em>”</a></li>
|
||||
<li><a href="http://hackerpublicradio.org/eps/hpr1951">HPR episode 1951 “<em>Some additional Bash tips</em>”</a></li>
|
||||
<li><a href="http://hackerpublicradio.org/eps/hpr2045">HPR episode 2045 “<em>Some other Bash tips</em>”</a></li>
|
||||
<li><a href="http://hackerpublicradio.org/eps/hpr2278">HPR episode 2278 “<em>Some supplementary Bash tips</em>”</a></li>
|
||||
<li><a href="http://hackerpublicradio.org/eps/hpr2293">HPR episode 2293 “<em>More supplementary Bash tips</em>”</a></li>
|
||||
</ol></li>
|
||||
<li>Resources:
|
||||
<ul>
|
||||
<li>Examples: <a href="hpr2639_bash9_ex1.sh">bash9_ex1.sh</a></li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user