396 lines
21 KiB
HTML
Executable File
396 lines
21 KiB
HTML
Executable File
<!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 - 17 (HPR Show 2719)</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 - 17 (HPR Show 2719)</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="#arrays-in-bash">Arrays in Bash</a></li>
|
||
<li><a href="#negative-indices-with-indexed-arrays">Negative indices with indexed arrays</a></li>
|
||
<li><a href="#concatenating-arrays">Concatenating arrays</a></li>
|
||
<li><a href="#parameter-expansion-operations-and-arrays">Parameter expansion operations and arrays</a><ul>
|
||
<li><a href="#substring-expansion">Substring expansion</a></li>
|
||
<li><a href="#list-keys-indices-or-subscripts">List keys (indices or subscripts)</a></li>
|
||
<li><a href="#length-of-string-or-array">Length of string or array</a></li>
|
||
<li><a href="#removing-leading-or-trailing-parts-that-match-a-pattern">Removing leading or trailing parts that match a pattern</a></li>
|
||
</ul></li>
|
||
<li><a href="#links">Links</a></li>
|
||
</ul>
|
||
</nav>
|
||
</header>
|
||
<h2 id="arrays-in-bash">Arrays in Bash</h2>
|
||
<p>This is the second of a small group of shows on the subject of arrays in Bash. It is also the seventeenth show in the <em>Bash Tips</em> sub-series.</p>
|
||
<p>In the last show we saw the two types of arrays, and learned about the multiple ways of creating them and populating them. We also looked at how array elements and entire arrays are accessed.</p>
|
||
<p>Now we want to continue looking at array access and some of the various parameter expansion operations available.</p>
|
||
<h2 id="negative-indices-with-indexed-arrays">Negative indices with indexed arrays</h2>
|
||
<p>When we looked at indexed array subscripts in the last episode we only considered positive numbers (and the <code>'*'</code> and <code>'@'</code> special subscripts). It is also possible to use negative numbers which index relative to the end of the array. The index <code>'-1'</code> means the last element, <code>'-2'</code> the penultimate, and so forth.</p>
|
||
<p>The downloadable script in <a href="hpr2719_bash17_ex1.sh">bash17_ex1.sh</a> demonstrates a use of negative indices:</p>
|
||
<pre><code>#!/bin/bash
|
||
|
||
#-------------------------------------------------------------------------------
|
||
# Example 1 for Bash Tips show 17: Negative indices
|
||
#-------------------------------------------------------------------------------
|
||
|
||
#
|
||
# Seed the Fibonacci sequence in an indexed array
|
||
#
|
||
declare -a fib=(0 1 1)
|
||
|
||
#
|
||
# Populate the rest up to (and including) the 20th element
|
||
#
|
||
for ((i = 3; i <= 20; i++)); do
|
||
fib[$i]=$((fib[i-2]+fib[i-1]))
|
||
done
|
||
|
||
#
|
||
# Show the whole array
|
||
#
|
||
echo "Fibonacci sequence"
|
||
echo "${fib[*]}"
|
||
echo
|
||
|
||
#
|
||
# Print a few elements working backwards
|
||
#
|
||
for i in {-1..-4}; do
|
||
echo "fib[$i] = ${fib[$i]}"
|
||
done
|
||
|
||
exit
|
||
</code></pre>
|
||
<p>The script seeds an indexed array called <code>'fib'</code> with the start of the <a href="https://en.wikipedia.org/wiki/Fibonacci_number" title="Wikipedia article on the Fibonacci sequence">Fibonacci sequence</a>. This sequence builds its elements by adding together the previous two, and that is what the <code>'for'</code> loop does, up to the 20th element.</p>
|
||
<p>Note that in the <code>'for'</code> loop an arithmetic expansion expression is used: <code>$((fib[i-2]+fib[i-1]))</code> which does not require dollar signs or curly brackets inside it.</p>
|
||
<p>The script prints all of the generated numbers then picks out the last four to demonstrate negative indexing.</p>
|
||
<p>Invoking the script results in the following:</p>
|
||
<pre><code>Fibonacci sequence
|
||
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765
|
||
|
||
fib[-1] = 6765
|
||
fib[-2] = 4181
|
||
fib[-3] = 2584
|
||
fib[-4] = 1597
|
||
</code></pre>
|
||
<h2 id="concatenating-arrays">Concatenating arrays</h2>
|
||
<p>There is no special syntax to concatenate one array to another. The simplest way to do this is using a command of the form:</p>
|
||
<pre><code>array1=( "${array2[@]}" "${array3[@]}" )</code></pre>
|
||
<p>The expression <code>"${array2[@]}"</code>, as we already know, returns the entirety of <code>'array2'</code> as a list of <em>words</em>. Effectively the parentheses are filled with the contents of each array as a list of separate <em>words</em>.</p>
|
||
<p>It is also possible to append an array to an already filled array thus:</p>
|
||
<pre><code>array1+=( "${array4[@]}" )</code></pre>
|
||
<p>The downloadable script in <a href="hpr2719_bash17_ex2.sh">bash17_ex2.sh</a> demonstrates array concatenation<a href="#fn1" class="footnote-ref" id="fnref1"><sup>1</sup></a>:</p>
|
||
<pre><code>#!/bin/bash
|
||
|
||
#-------------------------------------------------------------------------------
|
||
# Example 2 for Bash Tips show 17: Array concatenation
|
||
#-------------------------------------------------------------------------------
|
||
|
||
#
|
||
# Make three indexed arrays
|
||
#
|
||
declare -a a1 a2 a3
|
||
|
||
#
|
||
# Seed the random number generator
|
||
#
|
||
RANDOM=$(date +%N)
|
||
|
||
#
|
||
# Place 10 random numbers between 1..100 into the arrays a1 and a2
|
||
#
|
||
for ((i=1; i<=10; i++)); do
|
||
a1+=( $(( ( RANDOM % 100 ) + 1 )) )
|
||
a2+=( $(( ( RANDOM % 100 ) + 1 )) )
|
||
done
|
||
|
||
#
|
||
# Show the results
|
||
#
|
||
echo "a1: ${a1[*]}"
|
||
echo "a2: ${a2[*]}"
|
||
|
||
#
|
||
# Concatenate a1 and a2 into a3 and show the result
|
||
#
|
||
a3=( "${a1[@]}" "${a2[@]}" )
|
||
echo "a3: ${a3[*]}"</code></pre>
|
||
<p>Note the use of the special <code>'RANDOM'</code> variable which generates a (pseudo) random integer between 0 and 32767 on each access. To ensure the random sequence is not the same on each use the generator can be seeded which is what the command <code>RANDOM=$(date +%N)</code> does.</p>
|
||
<p>Invoking the script results in the following:</p>
|
||
<pre><code>a1: 34 9 70 68 5 36 63 2 11 84
|
||
a2: 13 87 58 10 33 88 35 51 45 83
|
||
a3: 34 9 70 68 5 36 63 2 11 84 13 87 58 10 33 88 35 51 45 83
|
||
</code></pre>
|
||
<h2 id="parameter-expansion-operations-and-arrays">Parameter expansion operations and arrays</h2>
|
||
<p>Back in episode <a href="https://hackerpublicradio.org/eps/hpr1648" title="Bash parameter manipulation">1648</a> in 2014 I described most of the Bash parameter expansion operations available, some in the context of arrays. Now I want to visit these again as well as a few more.</p>
|
||
<h3 id="substring-expansion">Substring expansion</h3>
|
||
<p>This performs two different functions:</p>
|
||
<ul>
|
||
<li>sub-strings can be selected from strings</li>
|
||
<li>array element subsets can be extracted from arrays</li>
|
||
</ul>
|
||
<p>The syntax of this feature is:</p>
|
||
<pre><code>${parameter:offset}
|
||
${parameter:offset:length}</code></pre>
|
||
<p>Both the <em>offset</em> and <em>length</em> are arithmetic expressions, which may be negative in some cases – which means to count backwards from the end of the string (or indexed array elements). A negative <em>offset</em> must be preceded by a space to stop Bash from interpreting it as another type of expansion. The negative <em>length</em> is only permitted with strings, not arrays. If <em>length</em> is omitted the remainder of the string or array after <em>offset</em> is returned.</p>
|
||
<p>When used with a single array element it is possible to extract parts of the string<a href="#fn2" class="footnote-ref" id="fnref2"><sup>2</sup></a>:</p>
|
||
<pre><code>$ declare -a planets=(mercury venus earth mars jupiter saturn uranus neptune)
|
||
$ echo "${planets[4]:2:3}" # middle letters of 'jupiter'
|
||
pit
|
||
$ echo "${planets[5]: -3:2}" # first two of the last 3 letters of 'saturn'
|
||
ur
|
||
$ echo "${planets[5]: -3}" # last 3 letters of 'saturn'
|
||
urn
|
||
$ echo "${planets[6]:1:-1}" # start at letter 1 up to but not including the last letter
|
||
ranu</code></pre>
|
||
<p>When used with the entirety of an indexed array (subscript <code>'@'</code> or <code>'*'</code>) then array elements are extracted:</p>
|
||
<pre><code>$ echo "${planets[@]:1:3}"
|
||
venus earth mars
|
||
$ echo "${planets[@]: -3:2}" # count back 3 from the end, display 2 elements
|
||
saturn uranus
|
||
$ echo "${planets[@]: -3}"
|
||
saturn uranus neptune</code></pre>
|
||
<p>As mentioned, the <em>length</em> may not be negative when using substring expansion to select indexed array elements.</p>
|
||
<p>Experiments have shown that elements can also be extracted from associative arrays with substring expansion, though since the element order is not defined the results may not be reliable.</p>
|
||
<hr />
|
||
<p><u>Note</u>: You might want to skip this section since it’s discussing a non-documented feature which shouldn’t be used in production.</p>
|
||
<p>The downloadable script in <a href="hpr2719_bash17_ex3.sh">bash17_ex3.sh</a> demonstrates a use of "substring expansion" with associative arrays:</p>
|
||
<pre><code>#!/bin/bash
|
||
|
||
#-------------------------------------------------------------------------------
|
||
# Example 3 for Bash Tips show 17: Using "substring expansion" to extract
|
||
# associative array elements
|
||
#-------------------------------------------------------------------------------
|
||
|
||
#
|
||
# Make two indexed arrays each containing 10 letters. Note: this is not the
|
||
# best way to do this!
|
||
#
|
||
declare -a a1=( $(echo {a..j}) )
|
||
declare -a a2=( $(echo {k..t}) )
|
||
|
||
#
|
||
# Build an associative array using one set of letters as subscripts and the
|
||
# other as the values
|
||
#
|
||
declare -A hash
|
||
for ((i=0; i<10; i++)); do
|
||
hash[${a1[$i]}]="${a2[$i]}"
|
||
done
|
||
|
||
#
|
||
# Display the associative array contents
|
||
#
|
||
echo "Contents of associative array 'hash'"
|
||
for key in "${!hash[@]}"; do
|
||
printf '%s=%s\n' "hash[$key]" "${hash[$key]}"
|
||
done
|
||
echo
|
||
|
||
#
|
||
# Walk the associative array printing pairs of values
|
||
#
|
||
echo "Pairs of values from array 'hash'"
|
||
for ((i=1; i<10; i+=2)); do
|
||
printf '%d: %s\n' "$i" "${hash[*]:$i:2}"
|
||
done</code></pre>
|
||
<p>The two indexed arrays <code>'a1'</code> and <code>'a2'</code> are filled with a series of 10 letters and these are then used to build the test associative array <code>'hash'</code>. This array is printed by the script to show what we did.</p>
|
||
<p>Note that we used the expression <code>"${!hash[@]}"</code> which returns a list of the subscripts for the <code>'hash'</code> array. We’ll look at this in more detail shortly.</p>
|
||
<p>Note also the use of <code>"${hash[*]:$i:2}"</code> using <code>'*'</code> in the final <code>'printf'</code>. This ensures that the two array elements returned are stored in one word. This allows us to use <code>'%s'</code> in the <code>'printf'</code> format to print the two values as one.</p>
|
||
<p>The final loop in the script uses substring expansion to display pairs of array elements. It does this successfully, but it may well be that more complex examples will not work.</p>
|
||
<p>Invoking the script results in the following:</p>
|
||
<pre><code>Contents of associative array 'hash'
|
||
hash[a]=k
|
||
hash[b]=l
|
||
hash[c]=m
|
||
hash[d]=n
|
||
hash[e]=o
|
||
hash[f]=p
|
||
hash[g]=q
|
||
hash[h]=r
|
||
hash[i]=s
|
||
hash[j]=t
|
||
|
||
Pairs of values from array 'hash'
|
||
1: k l
|
||
3: m n
|
||
5: o p
|
||
7: q r
|
||
9: s t
|
||
</code></pre>
|
||
<p>I tried another experiment like the previous one, this time using random words. I found this one worked too.</p>
|
||
<p>The downloadable script in <a href="hpr2719_bash17_ex4.sh">bash17_ex4.sh</a> contains this experiment. I will leave it for you to investigate further if this interests you.</p>
|
||
<hr />
|
||
<h3 id="list-keys-indices-or-subscripts">List keys (indices or subscripts)</h3>
|
||
<p>This expansion gives access to the indices, subscripts or keys of arrays. The syntax is:</p>
|
||
<pre><code>${!name[@]}
|
||
${!name[*]}</code></pre>
|
||
<p>If <em>name</em> is an array variable, expands to the list of array indices (keys) assigned in <em>name</em>. If <em>name</em> is not an array, expands to 0 if <em>name</em> is set and null otherwise. When <code>'@'</code> is used and the expansion appears within double quotes, each key expands to a separate word.</p>
|
||
<p>This is used in bash17_ex3.sh and bash17_ex4.sh to enable the associative arrays to be printed with their keys. The <code>'for'</code> loop uses:</p>
|
||
<pre><code>for key in "${!hash[@]}"; do</code></pre>
|
||
<p>The choice between <code>'*'</code> and <code>'@'</code> (when the expansion is written in double quotes) determines whether the keys are returned as one concatenated <em>word</em> or as a series of separate <em>words</em>.</p>
|
||
<h3 id="length-of-string-or-array">Length of string or array</h3>
|
||
<p>We saw this expansion in show <a href="https://hackerpublicradio.org/eps/hpr1648" title="Bash parameter manipulation">1648</a>. The syntax is:</p>
|
||
<pre><code>${#parameter}
|
||
|
||
${#name[@]}
|
||
${#name[*]}</code></pre>
|
||
<p>In the case where <em>parameter</em> is a simple variable this returns the length of the contents (i.e. the length of the string produced by expanding the parameter).</p>
|
||
<pre><code>$ veggie='kohlrabi'
|
||
$ echo "${#veggie}"
|
||
8</code></pre>
|
||
<p>In the case of an array with an index of <code>'*'</code> or <code>'@'</code> then it returns the number of elements in the array:</p>
|
||
<pre><code>$ declare -a vegs=(celeriac artichoke asparagus)
|
||
$ echo "${#vegs[@]}"
|
||
3
|
||
$ echo "${vegs} ${#vegs}"
|
||
celeriac 8</code></pre>
|
||
<p>Note that using just the name of an indexed array (without a subscript) returns the length of the first element (the <code>'[0]'</code> index is assumed, as we discussed last episode).</p>
|
||
<h3 id="removing-leading-or-trailing-parts-that-match-a-pattern">Removing leading or trailing parts that match a pattern</h3>
|
||
<p>Again we looked at these in show <a href="https://hackerpublicradio.org/eps/hpr1648" title="Bash parameter manipulation">1648</a>. There are four syntaxes listed in the manual:</p>
|
||
<pre><code>${parameter#word}
|
||
${parameter##word}
|
||
|
||
${parameter%word}
|
||
${parameter%%word}</code></pre>
|
||
<p>In these <em>word</em> is a <em>glob</em> pattern (or an <em>extglob</em> pattern if enabled). The form using one or two <code>'#'</code> characters after the <em>parameter</em> removes leading characters and the one using one or two <code>'%'</code> characters removes trailing characters.</p>
|
||
<p>The significance of the single versus the double <code>'#'</code> and <code>'%'</code> is that in the single case the shortest leading/trailing pattern is matched. In the double case the longest leading/trailing pattern is matched.</p>
|
||
<p>The downloadable script in <a href="hpr2719_bash17_ex5.sh">bash17_ex5.sh</a> demonstrates the use of removing leading and trailing strings matching patterns in a variety of ways:</p>
|
||
<pre><code>#!/bin/bash
|
||
|
||
#-------------------------------------------------------------------------------
|
||
# Example 5 for Bash Tips show 17: Trimming leading or trailing parts
|
||
#-------------------------------------------------------------------------------
|
||
|
||
#
|
||
# Make an indexed array of root vegetables
|
||
#
|
||
declare -a vegs=(celeriac artichoke asparagus parsnip mangelwurzel daikon turnip)
|
||
printf '%s\n\n' "${vegs[*]}"
|
||
|
||
#
|
||
# Demonstrate some trimming
|
||
#
|
||
echo "1. Removing the first character:"
|
||
echo "${vegs[@]#?}"
|
||
|
||
echo "2. Removing characters up to and including the first vowel:"
|
||
echo "${vegs[@]#*[aeiou]}"
|
||
|
||
echo "3. Removing characters up to and including the last vowel:"
|
||
printf '[%s] ' "${vegs[@]##*[aeiou]}"
|
||
echo
|
||
|
||
echo "4. Using an extglob pattern to remove several different leading patterns:"
|
||
shopt -s extglob
|
||
echo "${vegs[@]#@(cele|arti|aspa|mangel)}"
|
||
|
||
echo "5. Removing the last character":
|
||
echo "${vegs[@]%?}"
|
||
|
||
echo "6. Removing from the last vowel to the end:"
|
||
echo "${vegs[@]%[aeiou]*}"
|
||
|
||
echo "7. Removing from the first vowel to the end:"
|
||
printf '[%s] ' "${vegs[@]%%[aeiou]*}"
|
||
echo
|
||
|
||
echo "8. Using an extglob pattern to remove several different trailing patterns:"
|
||
echo "${vegs[@]%@(iac|oke|gus|nip|zel)}"
|
||
</code></pre>
|
||
<p>Note the use of <code>'printf'</code> in the script. This is used to enclose the results of the trimming in square brackets in order to make the results clearer. In some cases the trimming has removed the entirety of the string which would have been harder to see if this hadn’t been done.</p>
|
||
<p>Invoking the script results in the following:</p>
|
||
<pre><code>celeriac artichoke asparagus parsnip mangelwurzel daikon turnip
|
||
|
||
1. Removing the first character:
|
||
eleriac rtichoke sparagus arsnip angelwurzel aikon urnip
|
||
2. Removing characters up to and including the first vowel:
|
||
leriac rtichoke sparagus rsnip ngelwurzel ikon rnip
|
||
3. Removing characters up to and including the last vowel:
|
||
[c] [] [s] [p] [l] [n] [p]
|
||
4. Using an extglob pattern to remove several different leading patterns:
|
||
riac choke ragus parsnip wurzel daikon turnip
|
||
5. Removing the last character:
|
||
celeria artichok asparagu parsni mangelwurze daiko turni
|
||
6. Removing from the last vowel to the end:
|
||
celeri artichok asparag parsn mangelwurz daik turn
|
||
7. Removing from the first vowel to the end:
|
||
[c] [] [] [p] [m] [d] [t]
|
||
8. Using an extglob pattern to remove several different trailing patterns:
|
||
celer artich aspara pars mangelwur daikon tur
|
||
</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>Section on <a href="https://www.gnu.org/software/bash/manual/bash.html#Arrays">"Bash Arrays"</a></li>
|
||
</ul></li>
|
||
</ul>
|
||
<!--- -->
|
||
<ul>
|
||
<li>Linux Documentation Project: <a href="https://www.tldp.org/LDP/abs/html/index.html">Advanced Bash-Scripting Guide</a>
|
||
<ul>
|
||
<li><a href="https://www.tldp.org/LDP/abs/html/arrays.html">Chapter 27: Arrays</a></li>
|
||
</ul></li>
|
||
<li><p>Wikipedia article entitled <a href="https://en.wikipedia.org/wiki/Fibonacci_number">"<em>Fibonacci Number</em>"</a></p></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="https://hackerpublicradio.org/eps/hpr1648">HPR episode 1648 "<em>Bash parameter manipulation</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr1843">HPR episode 1843 "<em>Some Bash tips</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr1884">HPR episode 1884 "<em>Some more Bash tips</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr1903">HPR episode 1903 "<em>Some further Bash tips</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr1951">HPR episode 1951 "<em>Some additional Bash tips</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr2045">HPR episode 2045 "<em>Some other Bash tips</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr2278">HPR episode 2278 "<em>Some supplementary Bash tips</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr2293">HPR episode 2293 "<em>More supplementary Bash tips</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr2639">HPR episode 2639 "<em>Some ancillary Bash tips - 9</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr2649">HPR episode 2649 "<em>More ancillary Bash tips - 10</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr2659">HPR episode 2659 "<em>Further ancillary Bash tips - 11</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr2669">HPR episode 2669 "<em>Additional ancillary Bash tips - 12</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr2679">HPR episode 2679 "<em>Extra ancillary Bash tips - 13</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr2689">HPR episode 2689 "<em>Bash Tips - 14</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr2699">HPR episode 2699 "<em>Bash Tips - 15</em>"</a></li>
|
||
<li><a href="https://hackerpublicradio.org/eps/hpr2709">HPR episode 2709 "<em>Bash Tips - 16</em>"</a></li>
|
||
</ol></li>
|
||
</ul>
|
||
<!--- -->
|
||
<ul>
|
||
<li>Resources:
|
||
<ul>
|
||
<li>Examples: <a href="hpr2719_bash17_ex1.sh">bash17_ex1.sh</a>, <a href="hpr2719_bash17_ex2.sh">bash17_ex2.sh</a>, <a href="hpr2719_bash17_ex3.sh">bash17_ex3.sh</a>, <a href="hpr2719_bash17_ex4.sh">bash17_ex4.sh</a>, <a href="hpr2719_bash17_ex5.sh">bash17_ex5.sh</a></li>
|
||
</ul></li>
|
||
</ul>
|
||
<section class="footnotes">
|
||
<hr />
|
||
<ol>
|
||
<li id="fn1"><p>I realised I hadn’t discussed associative array concatenation as I was recording the audio. There is no simple way to concatenate these types of arrays. However, we will look at a way of doing this in the next episode.<a href="#fnref1" class="footnote-back">↩</a></p></li>
|
||
<li id="fn2"><p>I added the last example after realising there was no negative length when recording the audio.<a href="#fnref2" class="footnote-back">↩</a></p></li>
|
||
</ol>
|
||
</section>
|
||
</article>
|
||
</main>
|
||
</div>
|
||
</body>
|
||
</html>
|