Move under www to ease rsync
This commit is contained in:
9
www/eps/hpr2689/hpr2689_bash14_ex1.sh
Executable file
9
www/eps/hpr2689/hpr2689_bash14_ex1.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# An argument-printing 'for' loop demonstration
|
||||
#
|
||||
for arg do
|
||||
echo "$arg"
|
||||
done
|
||||
|
||||
9
www/eps/hpr2689/hpr2689_bash14_ex2.sh
Executable file
9
www/eps/hpr2689/hpr2689_bash14_ex2.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# A 'for' loop that uses multiple expressions for 'expr1' and 'expr3' courtesy
|
||||
# of the "comma operator"
|
||||
#
|
||||
for ((i = 1, j = 100; i <= 10; i++, j += 10)); do
|
||||
echo "$i $j"
|
||||
done
|
||||
22
www/eps/hpr2689/hpr2689_bash14_ex3.sh
Executable file
22
www/eps/hpr2689/hpr2689_bash14_ex3.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Two demonstrations of the use of 'break'
|
||||
#
|
||||
|
||||
echo "Demo 1"
|
||||
for i in {a..c}{1..3}; do
|
||||
echo "$i"
|
||||
[ "$i" == "b2" ] && break
|
||||
done
|
||||
|
||||
echo
|
||||
echo "Demo 2"
|
||||
for i in {a..c}{1..3}; do
|
||||
for j in {1..3}; do
|
||||
echo -n "$i "
|
||||
[ "$i" == "b2" ] && { echo; break 2; }
|
||||
done
|
||||
echo
|
||||
done
|
||||
|
||||
14
www/eps/hpr2689/hpr2689_bash14_ex4.sh
Executable file
14
www/eps/hpr2689/hpr2689_bash14_ex4.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# A demonstration of the use of 'continue'
|
||||
#
|
||||
|
||||
for i in {a..c}{1..3}; do
|
||||
for j in {1..3}; do
|
||||
echo -n "$i "
|
||||
[[ "$i" == b? ]] && { echo; continue 2; }
|
||||
done
|
||||
echo
|
||||
done
|
||||
|
||||
11
www/eps/hpr2689/hpr2689_bash14_ex5.sh
Executable file
11
www/eps/hpr2689/hpr2689_bash14_ex5.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# A demonstration that anything that generates a list of words or numbers can
|
||||
# be used in a 'for' loop
|
||||
#
|
||||
|
||||
for w in $(grep -E -v "'s$" /usr/share/dict/words | shuf -n 10); do
|
||||
echo "$w"
|
||||
done
|
||||
|
||||
251
www/eps/hpr2689/hpr2689_full_shownotes.html
Executable file
251
www/eps/hpr2689/hpr2689_full_shownotes.html
Executable file
@@ -0,0 +1,251 @@
|
||||
<!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>Bash Tips - 14 (HPR Show 2689)</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">Bash Tips - 14 (HPR Show 2689)</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="#more-about-loops">More about loops</a></li>
|
||||
<li><a href="#the-bash-for-loop">The Bash <code>for</code> loop</a><ul>
|
||||
<li><a href="#format-1">Format 1</a></li>
|
||||
<li><a href="#format-2">Format 2</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#the-break-and-continue-commands">The <code>break</code> and <code>continue</code> commands</a><ul>
|
||||
<li><a href="#the-break-command">The <code>break</code> command</a></li>
|
||||
<li><a href="#the-continue-command">The <code>continue</code> command</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#example">Example</a></li>
|
||||
<li><a href="#links">Links</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<h2 id="more-about-loops">More about loops</h2>
|
||||
<p>This is the fourteenth episode covering useful tips about using Bash. Episodes 9-13 covered <em>Making Decisions in Bash</em> and in these episodes we looked at <code>while</code> and <code>until</code> loops, but not <code>for</code> loops. This episode is making good this deficiency, and is also looking at <code>break</code> and <code>continue</code> which are very useful when using loops.</p>
|
||||
<h2 id="the-bash-for-loop">The Bash <code>for</code> loop</h2>
|
||||
<p>This command has two forms described as syntax diagrams below. The diagrams are taken from the <a href="https://www.gnu.org/software/bash/manual/bash.html#Looping-Constructs" title="Bash Looping Constructs">GNU Bash Manual</a>:</p>
|
||||
<h3 id="format-1">Format 1</h3>
|
||||
<pre><code>for name [ [in [words …] ] ; ] do commands; done</code></pre>
|
||||
<p>If written with the <code>'in words'</code> part <code>'words'</code> is a literal list or expandable item which provides a list. The loop cycles once for each member of the list, setting variable <code>'name'</code> to each successive member and executing <code>'commands'</code> at each iteration.</p>
|
||||
<pre><code>for colour in red green blue; do
|
||||
echo "$colour"
|
||||
done</code></pre>
|
||||
<p>This will output the three colour names, one per line.</p>
|
||||
<pre><code>for file in *.mp3; do
|
||||
echo "$file"
|
||||
done</code></pre>
|
||||
<p>In this case <code>'*.mp3'</code> will expand to a list of the files in the current directory which have an <code>'mp3'</code> extension.</p>
|
||||
<p>Such a list might be empty, and so the form with a null list is legal:</p>
|
||||
<pre><code>for name in ; do command; done</code></pre>
|
||||
<p>In this case the loop will not run at all.</p>
|
||||
<p>This loop may be written without the <code>'in words'</code> part which has a special meaning. The loop cycles through all of the positional parameters. The same effect can be obtained with:</p>
|
||||
<pre><code>for name in "$@"; do command; done</code></pre>
|
||||
<p>The following very simple downloadable example <a href="hpr2689_bash14_ex1.sh">bash14_ex1.sh</a> demonstrates the use of this form.</p>
|
||||
<pre><code>$ cat bash14_ex1.sh
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# An argument-printing 'for' loop demonstration
|
||||
#
|
||||
for arg do
|
||||
echo "$arg"
|
||||
done
|
||||
</code></pre>
|
||||
<p>Invoking the script with a list of words as arguments results in the words being echoed back one per line:</p>
|
||||
<pre><code>$ ./bash14_ex1.sh Let joy be unconfined
|
||||
Let
|
||||
joy
|
||||
be
|
||||
unconfined</code></pre>
|
||||
<p>The return status of the <code>for</code> command is the exit status of the last command that executes within it. If there are no items in the expansion of words, no commands are executed, and the return status is zero.</p>
|
||||
<h3 id="format-2">Format 2</h3>
|
||||
<pre><code>for (( expr1 ; expr2 ; expr3 )) ; do commands ; done</code></pre>
|
||||
<p>This <code>for</code> loop format uses numeric expressions to determine how many times to loop.</p>
|
||||
<ul>
|
||||
<li><code>'expr1'</code> is an arithmetic expression which is evaluated at the start; it often consists of a variable being set to a value.</li>
|
||||
<li><code>'expr2'</code> is also an arithmetic expression which is evaluated at each iteration of the loop; each time it evaluates to a non-zero value the commands in the loop are executed.</li>
|
||||
<li><code>'expr3'</code> is another arithmetic expression which is evaluated each time <code>'expr2'</code> evaluates to a non-zero value.</li>
|
||||
</ul>
|
||||
<p>For example:</p>
|
||||
<pre><code>for ((i = 1; i < 10; i++)); do
|
||||
echo "$i"
|
||||
done</code></pre>
|
||||
<p>This will output the numbers 1-9, one per line.</p>
|
||||
<p>There is a lot of flexibility allowed in the expressions between the double parentheses since the rules of <a href="https://www.gnu.org/software/bash/manual/bash.html#Shell-Arithmetic" title="Bash Shell Arithmetic">Shell Arithmetic</a> apply. Examples are:</p>
|
||||
<ul>
|
||||
<li>Spaces are not mandated and can be used as required for clarity</li>
|
||||
<li>Variable references do not need leading <code>'$'</code> symbols</li>
|
||||
<li>Any of the shell arithmetic operators can be used</li>
|
||||
</ul>
|
||||
<p>For example:</p>
|
||||
<pre><code>for ((i = ((78+20)/2)-(4*12); i != 10; i ++)); do
|
||||
echo $i
|
||||
done</code></pre>
|
||||
<p>This one initialises <code>'i'</code> with a calculation, and tests to see if it is not 10 at every iteration.</p>
|
||||
<p>A more involved example:</p>
|
||||
<pre><code>$ for ((i = 1, j = 100; i <= 10; i++, j += 10)); do
|
||||
> echo "$i $j"
|
||||
> done
|
||||
1 100
|
||||
2 110
|
||||
3 120
|
||||
4 130
|
||||
5 140
|
||||
6 150
|
||||
7 160
|
||||
8 170
|
||||
9 180
|
||||
10 190</code></pre>
|
||||
<p>We show this one being typed as a multi-line command at the command line. It sets <code>'i'</code> to 1 and <code>'j'</code> to 100 using the comma operator which lets you join multiple unrelated expressions together. It loops until <code>'i'</code> is 10 and at each iteration it increments <code>'i'</code> by 1 and <code>'j'</code> by 10, again using the comma operator. Incrementing <code>'j'</code> is done using the assignment operator <code>'+='</code>.</p>
|
||||
<p>A downloadable copy is included with this episode if you would like to experiment with this <code>for</code> command: <a href="hpr2689_bash14_ex2.sh">bash14_ex2.sh</a>.</p>
|
||||
<p>If any of <code>'expr1'</code>, <code>'expr2'</code> and <code>'expr3'</code> is missing it evaluates to 1. Thus, the following command defines an infinite loop:</p>
|
||||
<pre><code>for (( ; ; )) ; do commands ; done</code></pre>
|
||||
<p>The return value of this type of <code>for</code> command is the exit status of the last command in <code>'commands'</code> that is executed, or false if any of the expressions is invalid.</p>
|
||||
<h2 id="the-break-and-continue-commands">The <code>break</code> and <code>continue</code> commands</h2>
|
||||
<p>We have encountered these before in passing. They are both builtin commands inherited from the <a href="https://www.gnu.org/software/bash/manual/bash.html#Bourne-Shell-Builtins" title="Bourne Shell Builtins">Bourne Shell</a>. They are both for changing the sequence of execution of a loop (<code>for</code>, <code>while</code>, <code>until</code>, or <code>select</code> - we will look at the <code>select</code> command in a later episode).</p>
|
||||
<h3 id="the-break-command">The <code>break</code> command</h3>
|
||||
<pre><code>break [n]</code></pre>
|
||||
<p>Exits from a loop. If <code>'n'</code> is supplied it must be an integer number greater than or equal to 1. It specifies that the <code>n</code>th enclosing loop must be exited.</p>
|
||||
<p>For example:</p>
|
||||
<pre><code>for i in {a..c}{1..3}; do
|
||||
echo "$i"
|
||||
[ "$i" == "b2" ] && break
|
||||
done</code></pre>
|
||||
<p>This outputs one of the letters followed by one of the numbers until the combination equals <code>'b2'</code> at which point the <code>break</code> command is issued and the loop is exited. See episode <a href="http://hackerpublicradio.org/eps/hpr1884" title="Some more Bash tips">1884</a> for details of the <a href="https://www.gnu.org/software/bash/manual/bash.html#Brace-Expansion" title="Bash Brace Expansion">Brace Expansion</a> used here.</p>
|
||||
<pre><code>a1
|
||||
a2
|
||||
a3
|
||||
b1
|
||||
b2</code></pre>
|
||||
<p>This example contains a loop within a loop. The inner loop simply repeats the current value of <code>'i'</code> three times using <code>'echo -n</code>’ to suppress the newline. We want to exit both loops whenever <code>'i'</code> gets to <code>'b2'</code>.</p>
|
||||
<pre><code>for i in {a..c}{1..3}; do
|
||||
for j in {1..3}; do
|
||||
echo -n "$i "
|
||||
[ "$i" == "b2" ] && { echo; break 2; }
|
||||
done
|
||||
echo
|
||||
done</code></pre>
|
||||
<p>Note we include an <code>echo</code> with the <code>break</code> to add the newline to the partially completed line:</p>
|
||||
<pre><code>a1 a1 a1
|
||||
a2 a2 a2
|
||||
a3 a3 a3
|
||||
b1 b1 b1
|
||||
b2</code></pre>
|
||||
<p>A downloadable script is available containing versions of the two loops we have just looked at in case you would like to experiment with them: <a href="hpr2689_bash14_ex3.sh">bash14_ex3.sh</a>.</p>
|
||||
<h3 id="the-continue-command">The <code>continue</code> command</h3>
|
||||
<pre><code>continue [n]</code></pre>
|
||||
<p>Resumes the next iteration of a loop. If <code>'n'</code> is supplied it must be an integer number greater than or equal to 1. It specifies that the <code>n</code>th enclosing loop must be resumed.</p>
|
||||
<p>For example, the following downloadable file <a href="hpr2689_bash14_ex4.sh">bash14_ex4.sh</a>:</p>
|
||||
<pre><code>$ cat bash14_ex4.sh
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# A demonstration of the use of 'continue'
|
||||
#
|
||||
|
||||
for i in {a..c}{1..3}; do
|
||||
for j in {1..3}; do
|
||||
echo -n "$i "
|
||||
[[ "$i" == b? ]] && { echo; continue 2; }
|
||||
done
|
||||
echo
|
||||
done
|
||||
</code></pre>
|
||||
<p>This is a variant of the previous example with the same nested loops and potentially the same output. The difference is that when the contents of variable <code>'i'</code> begins with a <code>'b'</code> the <code>continue 2</code> command is invoked so that only the first instance is printed and the outer loop resumes with the next letter/number combination. Note that we are using the <em>extended test</em> here with a glob-style string match.</p>
|
||||
<p>Invoking the script returns the following:</p>
|
||||
<pre><code>$ ./bash14_ex4.sh
|
||||
a1 a1 a1
|
||||
a2 a2 a2
|
||||
a3 a3 a3
|
||||
b1
|
||||
b2
|
||||
b3
|
||||
c1 c1 c1
|
||||
c2 c2 c2
|
||||
c3 c3 c3</code></pre>
|
||||
<h2 id="example">Example</h2>
|
||||
<p>The final downloadable script <a href="hpr2689_bash14_ex5.sh">bash14_ex5.sh</a> is not very complex but shows that a list in the first format <code>for</code> command can be anything. This example uses the much-referenced <code>/usr/share/dict/words</code> with the <code>shuf</code> command to return 10 words. I first use <code>grep</code> to omit all the words that end with a possessive <code>"'s"</code> because so many of these seem ridiculous (when would you ever use <code>"loggerhead's"</code> for example?):</p>
|
||||
<pre><code>$ cat bash14_ex5.sh
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# A demonstration that anything that generates a list of words or numbers can
|
||||
# be used in a 'for' loop
|
||||
#
|
||||
|
||||
for w in $(grep -E -v "'s$" /usr/share/dict/words | shuf -n 10); do
|
||||
echo "$w"
|
||||
done
|
||||
</code></pre>
|
||||
<p>Invoking the script returns a list of random words:</p>
|
||||
<pre><code>$ ./bash14_ex5.sh
|
||||
transplants
|
||||
fireplug
|
||||
dismissals
|
||||
honcho
|
||||
beefiest
|
||||
sensational
|
||||
junkets
|
||||
steads
|
||||
troglodyte
|
||||
burkas</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#Looping-Constructs">"Bash Looping Constructs"</a></li>
|
||||
<li><a href="https://www.gnu.org/software/bash/manual/bash.html#Shell-Arithmetic">"Bash Shell Arithmetic"</a></li>
|
||||
<li><a href="https://www.gnu.org/software/bash/manual/bash.html#Bourne-Shell-Builtins">"Bourne Shell Builtins"</a></li>
|
||||
<li><a href="https://www.gnu.org/software/bash/manual/bash.html#Brace-Expansion">"Bash Brace Expansion"</a></li>
|
||||
</ul></li>
|
||||
<li><p><a href="http://hackerpublicradio.org/series.php?id=42">HPR series: <em>Bash Scripting</em></a></p></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>
|
||||
<li><a href="http://hackerpublicradio.org/eps/hpr2639">HPR episode 2639 "<em>Some ancillary Bash tips - 9</em>"</a></li>
|
||||
<li><a href="http://hackerpublicradio.org/eps/hpr2649">HPR episode 2649 "<em>More ancillary Bash tips - 10</em>"</a></li>
|
||||
<li><a href="http://hackerpublicradio.org/eps/hpr2659">HPR episode 2659 "<em>Further ancillary Bash tips - 11</em>"</a></li>
|
||||
<li><a href="http://hackerpublicradio.org/eps/hpr2669">HPR episode 2669 "<em>Additional ancillary Bash tips - 12</em>"</a></li>
|
||||
<li><a href="http://hackerpublicradio.org/eps/hpr2679">HPR episode 2679 "<em>Extra ancillary Bash tips - 13</em>"</a></li>
|
||||
</ol></li>
|
||||
</ul>
|
||||
<!--- -->
|
||||
<ul>
|
||||
<li>Resources:
|
||||
<ul>
|
||||
<li>Examples: <a href="hpr2689_bash14_ex1.sh">bash14_ex1.sh</a>, <a href="hpr2689_bash14_ex2.sh">bash14_ex2.sh</a>, <a href="hpr2689_bash14_ex3.sh">bash14_ex3.sh</a>, <a href="hpr2689_bash14_ex4.sh">bash14_ex4.sh</a>, <a href="hpr2689_bash14_ex5.sh">bash14_ex5.sh</a></li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user