Move under www to ease rsync

This commit is contained in:
2025-10-29 10:51:15 +01:00
parent 2bb22c7583
commit 30ad62e938
890 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
#-------------------------------------------------------------------------------
# Example 1 for Bash Tips show 21: the environment
#-------------------------------------------------------------------------------
# Not expected to be in the environment
bt211C=somedata
echo "Args: $*"
printenv
exit

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env bash
#-------------------------------------------------------------------------------
# Example 2 for Bash Tips show 21: the environment
#-------------------------------------------------------------------------------
BTversion='21'
export BTversion
echo "** Using 'grep' with 'env'"
env | grep -E '(EDITOR|SHELL|BTversion)='
echo
echo "** Using 'printenv' with arguments"
printenv EDITOR SHELL BTversion
echo
echo "** Using 'grep' with 'export'"
export | grep -E '(EDITOR|SHELL|BTversion)='
echo
echo "** Using 'grep' with 'declare'"
declare -x | grep -E '(EDITOR|SHELL|BTversion)='
exit

View File

@@ -0,0 +1,10 @@
#!/usr/bin/awk -f
#-------------------------------------------------------------------------------
# Example 3 for Bash Tips show 21: printing the environment in Awk
#-------------------------------------------------------------------------------
BEGIN{
for (n in ENVIRON)
printf "ENVIRON[%s]=%s\n",n,ENVIRON[n]
}

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env bash
#-------------------------------------------------------------------------------
# Example 4 for Bash Tips show 21: a way of showing environment variables
#-------------------------------------------------------------------------------
#
# We expect one or more arguments
#
if [[ $# = 0 ]]; then
echo "Usage: $0 variable_name"
exit 1
fi
#
# Loop through the arguments reporting their attributes with 'declare'
#
for arg; do
declare -p "$arg"
done
exit

View File

@@ -0,0 +1,18 @@
#-------------------------------------------------------------------------------
# Example 5 for Bash Tips show 21: a few things exported in my .bashrc
#-------------------------------------------------------------------------------
#
# The PATH variable gets my local ~/bin directory added to it
#
export PATH="${PATH}:$HOME/bin"
#
# The above is the older way of doing this. It is possible to write the
# following using '+=' to concatenate a string onto a variable:
# export PATH+=":$HOME/bin"
#
# Some tools need a default editor. The only one for me is Vim
#
export EDITOR=/usr/bin/vim
export VISUAL=/usr/bin/vim

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env bash
#-------------------------------------------------------------------------------
# Example 6 for Bash Tips show 21: a poor way to make a configuration file
#-------------------------------------------------------------------------------
#
# Example configuration file using 'export'
#
CFG1='bash21_ex6_1.cfg'
if [[ ! -e $CFG1 ]]; then
echo "Unable to find $CFG1"
exit 1
fi
#
# Alternative configuration file using 'declare', converted from the other one
#
CFG2='bash21_ex6_2.cfg'
#
# Strip out all of the 'export' commands with 'sed' in a process substitution,
# turning the lines into simple variable declarations. Use 'source' to obey
# all of the resulting commands
#
source <(sed 's/^export //' $CFG1)
#
# Scan the (simple) variables beginning with '_CFG_' and convert them into
# a portable form by saving the output of 'declare -p'
#
declare -p "${!_CFG_@}" > $CFG2
#
# Now next time we can 'source' this file instead when we want the variables
#
cat $CFG2
exit

View File

@@ -0,0 +1,16 @@
export _CFG_PROJECT="Bash_Tips__21"
export _CFG_HOSTID=225
export _CFG_HOSTNAME="Dave Morriss"
export _CFG_SUMMARY="Environment variables"
export _CFG_TAGS="Bash,variable,environment"
export _CFG_EXPLICIT="Yes"
export _CFG_FILES=(hpr____.html hpr____.tbz)
export _CFG_STRUCTURE="Tree"
export _CFG_SERIES="Bash Scripting"
export _CFG_NOTETYPE="HTML"
export _CFG_SUMADDED="No"
export _CFG_INOUT="No"
export _CFG_EMAIL="blah@blah"
export _CFG_TITLE="Bash Tips - 21"
export _CFG_STATUS="Editing"
export _CFG_SLOT=""

View File

@@ -0,0 +1,16 @@
declare -- _CFG_EMAIL="blah@blah"
declare -- _CFG_EXPLICIT="Yes"
declare -a _CFG_FILES=([0]="hpr____.html" [1]="hpr____.tbz")
declare -- _CFG_HOSTID="225"
declare -- _CFG_HOSTNAME="Dave Morriss"
declare -- _CFG_INOUT="No"
declare -- _CFG_NOTETYPE="HTML"
declare -- _CFG_PROJECT="Bash_Tips__21"
declare -- _CFG_SERIES="Bash Scripting"
declare -- _CFG_SLOT=""
declare -- _CFG_STATUS="Editing"
declare -- _CFG_STRUCTURE="Tree"
declare -- _CFG_SUMADDED="No"
declare -- _CFG_SUMMARY="Environment variables"
declare -- _CFG_TAGS="Bash,variable,environment"
declare -- _CFG_TITLE="Bash Tips - 21"

View File

@@ -0,0 +1,567 @@
<!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 - 21 (HPR Show 3013)</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 - 21 (HPR Show 3013)</h1>
<h2 class="subtitle">Environment variables</h2>
<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="#the-environment-more-collateral-bash-tips">The Environment <small><small>(More collateral Bash tips)</small></small></a><ul>
<li><a href="#overview">Overview</a><ul>
<li><a href="#using-the-environment">Using the environment</a></li>
<li><a href="#viewing-the-environment">Viewing the environment</a></li>
<li><a href="#changing-variables-in-the-environment">Changing variables in the environment</a></li>
</ul></li>
</ul></li>
<li><a href="#a-detailed-look">A detailed look</a><ul>
<li><a href="#temporary-addition-to-a-commands-environment">Temporary addition to a commands environment</a></li>
<li><a href="#commands-relating-to-the-environment">Commands relating to the environment</a><ul>
<li><a href="#the-printenv-command">The <code>printenv</code> command</a></li>
<li><a href="#the-env-command">The <code>env</code> command</a></li>
<li><a href="#the-declare-command">The <code>declare</code> command</a></li>
<li><a href="#the-export-command">The <code>export</code> command</a></li>
<li><a href="#the-set-command">The <code>set</code> command</a></li>
<li><a href="#example-using-set--k">Example: using <code>set -k</code></a></li>
</ul></li>
<li><a href="#using-environment-variables">Using environment variables</a></li>
</ul></li>
<li><a href="#examples">Examples</a><ul>
<li><a href="#various-ways-of-displaying-the-environment">Various ways of displaying the environment</a></li>
<li><a href="#accessing-the-environment-in-an-awk-script">Accessing the environment in an <code>awk</code> script</a></li>
<li><a href="#passing-temporary-environment-variables">Passing temporary environment variables</a></li>
<li><a href="#using-export-in-bash-configuration-files">Using <code>export</code> in Bash configuration files</a></li>
<li><a href="#a-simple-configuration-file-for-a-bash-script">A simple configuration file for a Bash script</a></li>
</ul></li>
<li><a href="#links">Links</a></li>
</ul>
</nav>
</header>
<h2 id="the-environment-more-collateral-bash-tips">The Environment <small><small>(More collateral Bash tips)</small></small></h2>
<h3 id="overview">Overview</h3>
<p>You will probably have seen references to <em>The Environment</em> in various contexts relating to shells, shell scripts, scripts in other languages and compiled programs.</p>
<p>In Unix and Unix-like operating systems an environment is maintained by the shell, and we will be looking at how Bash deals with this in this episode. When a script, program or subprocess is invoked it is given an array of strings called the <em>environment</em>. This is a list of name-value pairs, of the form <code>name=value</code>.</p>
<h4 id="using-the-environment">Using the environment</h4>
<p>The environment is used to convey various pieces of information to the executing script or program. For example, two standard variables provided by the shell are <code>'HOME'</code>, which is set to the current users home directory and <code>'PWD</code>, set to the current working directory. The shell user can set, change, remove and view environment variables for their own purposes as we will see in this episode. The Bash shell itself creates and in some cases manages environment variables.</p>
<p>The environment contains global data which is passed down to subprocesses (<em>child</em> processes) by copying. However, it is not possible for a subprocess to pass information <b>back</b> to the superior (<em>parent</em>) process.</p>
<h4 id="viewing-the-environment">Viewing the environment</h4>
<p>You can view the environment in a number of ways.</p>
<ul>
<li><p>From the command line the command <code>printenv</code> can do this (this is usually but not always a stand-alone command: its <code>/usr/bin/printenv</code> on my Debian system). We will look at this command later.</p></li>
<li><p>The command <code>env</code> without any arguments does the same thing as <code>printenv</code> without arguments. This is actually a tool to run a program in a modified environment which we will look at later. The environment printing capability can be regarded as more of a bonus feature.</p></li>
<li><p>Scripting languages like <code>awk</code> (as well as Python and Perl, to name just a few) can view and manipulate the environment.</p></li>
<li><p>Compiled languages such as <code>C</code> can do this too of course.</p></li>
<li><p>There are other commands that will show the environment, and we will look at some of these briefly.</p></li>
</ul>
<h4 id="changing-variables-in-the-environment">Changing variables in the environment</h4>
<p>The variables in the environment are not significantly different from the <em>shell parameters</em> we have seen throughout this Bash Tips series. The only difference is that they are marked for <em>export</em> to commands and sub-shells. You will often see variables (or parameters) in the environment referred to as <em>environment variables</em>. The Bash manual makes a distinction between ordinary parameters (variables) and environment variables, but many other sources are less precise about this in my experience.</p>
<p>The standard variables in the environment have upper-case names (<code>HOME</code>, <code>SHELL</code>, <code>PWD</code>, etc), but there is no reason why a variable you create should not be in lower or mixed case. In fact, the Bash manual suggests that you should avoid using all upper-case names so as not to clash with Bashs variables.</p>
<p>Variables can be created and changed a number of ways.</p>
<ul>
<li>They can be set up at login time (globally or locally) through various standard configuration files. It is intended to look at this subject in an upcoming episode so we will leave discussing the subject until then.</li>
<li>By preceding the command or script invocation with <em>name=value</em> expressions which will temporarily place these variables into the environment for the command</li>
<li>Using the <code>export</code> command</li>
<li>Using the <code>declare</code> command with the <code>-x</code> option</li>
<li>The value of an environment variable (once established) can be changed at any time in the sub-shell with a command like <code>myvar=42</code>, just as for a normal variable</li>
<li>The <code>export</code> command can also be used to turn off the <em>export</em> marker on a variable</li>
<li>Deletion is performed with the <code>unset</code> command (as seen earlier in the series)</li>
</ul>
<p>We will look at all of these features in more detail later in the episode.</p>
<h2 id="a-detailed-look">A detailed look</h2>
<h3 id="temporary-addition-to-a-commands-environment">Temporary addition to a commands environment</h3>
<p>As summarised above, a command can be preceded by <em>name=value</em> definitions, and these set environment variables while the command is running.</p>
<p>For example, if an awk script has been placed in <code>/tmp</code> like this:</p>
<pre><code>$ cat &gt; /tmp/awktest.awk
BEGIN { print &quot;Hello World!&quot; }
CTRL+D</code></pre>
<p><small>(where <code>CTRL+D</code> means to press <code>D</code> while holding down the <code>CTRL</code> key)</small>.</p>
<p>It is now possible to invoke <code>awk</code> to execute this file by giving it the environment variable <code>AWKPATH</code>. This is a list of directories where <code>awk</code> looks to find script files.</p>
<pre><code>$ AWKPATH=/tmp awk -f awktest
Hello World!</code></pre>
<p>Note that:</p>
<ol type="1">
<li>The file is found even though the <code>'.awk'</code> part has been omitted; this is something that <code>awk</code> does when searching <code>AWKPATH</code></li>
<li>The setting of <code>AWKPATH</code> is separated from the <code>awk</code> command by a space - not a semi-colon. (If a semi-colon had been used then there would have been two statements on the line, which would not have achieved what was wanted.)</li>
<li>The variable <code>AWKPATH</code> is not changed in the parent process (the process that ran <code>awk</code>), the change is temporary, is in the child process, and lasts only as long as the command runs</li>
</ol>
<h3 id="commands-relating-to-the-environment">Commands relating to the environment</h3>
<h4 id="the-printenv-command">The <code>printenv</code> command</h4>
<p>The <code>printenv</code> command without arguments lists all the environment variables. It may be followed by a list of variable names, in which case the output is restricted to these variables.</p>
<p>When no arguments are given the output consists of <em>name=value</em> pairs, but if variable names are specified just the values are listed.</p>
<p>This command might be built into the shell, but this is not the case with Bash.</p>
<h4 id="the-env-command">The <code>env</code> command</h4>
<p>This is a shell command which will print a list of environment variables or run another command in an altered environment.</p>
<pre><code>env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]</code></pre>
<p>Without the <code>COMMAND</code> part <code>env</code> is functionally equivalent to <code>printenv</code>.</p>
<p>Options are:</p>
<table>
<thead>
<tr class="header">
<th>Option</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><b>-</b>, <b>-i</b>, <b>--ignore-environment</b></td>
<td>start with an empty environment</td>
</tr>
<tr class="even">
<td><b>-0</b>, <b>--null</b></td>
<td>(zero) end each output line with 0 byte rather than newline</td>
</tr>
<tr class="odd">
<td><b>-u</b>, <b>--unset=<em>NAME</em></b></td>
<td>remove variable from the environment</td>
</tr>
<tr class="even">
<td><b>-C</b>, <b>--chdir=<em>DIR</em></b></td>
<td>change working directory to <em>DIR</em></td>
</tr>
<tr class="odd">
<td><b>-S</b>, <b>--split-string=<em>S</em></b></td>
<td>process and split <em>S</em> into separate arguments;</td>
</tr>
<tr class="even">
<td></td>
<td>used to pass multiple arguments on shebang lines</td>
</tr>
<tr class="odd">
<td><b>-v</b>, <b>--debug</b></td>
<td>show verbose information for each processing step</td>
</tr>
</tbody>
</table>
<p>The <code>NAME=VALUE</code> part is where environment variables are defined for the command being run.</p>
<p>The <code>env</code> command is often used in shell scripts to run the correct <em>interpreter</em> on the <em>hash bang</em> or <em>shebang</em> line (the first line of the file which begins with <code>'#!'</code>) without needing to know its path. It <strong>is</strong> necessary to know the path of <code>env</code> but this is usually (almost invariably) <code>/usr/bin/env</code>.</p>
<p>For example, to run a <code>python3</code> script you might begin with:</p>
<pre><code>#!/usr/bin/env python3</code></pre>
<p>The <code>-S</code> option is required if the interpreter needs options of its own. For example:</p>
<pre><code>$ cat awktest1
#!/usr/bin/env awk -f
BEGIN{ print &quot;Hello World&quot; }
$ ./awktest1
/usr/bin/env: awk -f: No such file or directory
/usr/bin/env: use -[v]S to pass options in shebang lines
$ cat awktest2
#!/usr/bin/env -S awk -f
BEGIN{ print &quot;Hello World&quot; }
$ ./awktest2
Hello World</code></pre>
<p>Script <code>awktest1</code> fails because <code>env</code> misunderstands <code>'awk -f'</code> whereas <code>awktest2</code>, which uses <code>-S</code> works fine.</p>
<p>The <code>env</code> command can be run from the command line as a means of running a command with a special environment. For example:</p>
<pre><code>$ env MSG=&quot;Hello&quot; printenv MSG
Hello
$ printenv MSG</code></pre>
<p>This defines environment variable <code>MSG</code> and runs <code>'printenv MSG'</code> to show its value, which is destroyed as soon as the command has finished. The second <code>printenv</code> does nothing because <code>MSG</code> has gone.</p>
<p>This can also be demonstrated thus:</p>
<pre><code>$ env -vi MSG=&quot;Hello&quot; printenv
cleaning environ
setenv: MSG=Hello
executing: printenv
arg[0]= printenv
MSG=Hello</code></pre>
<p>Here debug mode is on, and the <code>'-i'</code> option clears the environment of all but <code>MSG</code>. We dont specify <code>MSG</code> as an argument this time; its unnecessary because that variable is all there is in the child environment.</p>
<p>Consult the <a href="https://www.gnu.org/software/coreutils/manual/" title="GNU Coreutils Manual">GNU Coreutils Manual</a> for more details of the <code>env</code> command. Note that the version of <code>env</code> being described here is 8.30.</p>
<h4 id="the-declare-command">The <code>declare</code> command</h4>
<p>As we saw earlier in this series, <code>declare</code> can be used to create variables (and arrays). If the <code>'-x'</code> option is added to the command then the <u>variables</u> created are also marked for export to the environment used by subsequent commands. Note that arrays <strong>cannot</strong> be exported in any current versions of Bash. It was apparently planned to do this in the past, but it has not been implemented.</p>
<p>The option <code>'+x'</code> can also remove the indicator that makes a variable exported.</p>
<p>As expected <code>declare -p</code> can be used to show the <code>declare</code> command required to create a variable and the same applies to looking at environment variables using <code>declare -p -x</code>.</p>
<h4 id="the-export-command">The <code>export</code> command</h4>
<p>This command marks variables to be passed to child processes in the environment.</p>
<pre><code>export [-fn] [-p] [name[=value] ...]</code></pre>
<p>By default the <em>name</em>s refer to shell variables, which can be given a value if desired.</p>
<p>Options are:</p>
<table>
<thead>
<tr class="header">
<th>Option</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><b>-n</b></td>
<td>the <em>name</em> arguments are marked <b>not</b> to be exported</td>
</tr>
<tr class="even">
<td><b>-f</b></td>
<td>the <em>name</em> arguments are the names of defined shell functions</td>
</tr>
<tr class="odd">
<td><b>-p</b></td>
<td>displays output in a form that may be reused as input (see <code>declare</code>)</td>
</tr>
</tbody>
</table>
<p>Writing <code>'export -p'</code> with no arguments causes the environment to be displayed in a similar way to <code>'declare -x -p'</code>.</p>
<p>Looking again at the <code>awk</code> example from earlier we could use <code>export</code> to set <code>AWKPATH</code>, but the setting will persist after the process running <code>awk</code> has finished:</p>
<pre><code>$ export AWKPATH=/tmp
$ awk -f awktest
Hello World!
$ echo $AWKPATH
/tmp</code></pre>
<p>You might see <code>export</code> being used in the following way in older scripts:</p>
<pre><code>TZ=&#39;Europe/London&#39;; export TZ</code></pre>
<p>This is perfectly acceptable, but the single-statement form is most common in more recent scripts.</p>
<h4 id="the-set-command">The <code>set</code> command</h4>
<p>We have looked at some of the features that this command offers in other contexts but have not yet examined it in detail. This detailed analysis is overdue, but (for brevity) will be left until a later episode of <em>Bash Tips</em>.</p>
<p>For now we will look at <code>set</code> in the context of environment variables.</p>
<p>When <code>set</code> is used without any options or arguments then it performs the following function (quoted from the Gnu Bash Manual):</p>
<blockquote>
<p><code>set</code> displays the names and values of all shell variables and functions, sorted according to the current locale, in a format that may be reused as input for setting or resetting the currently-set variables.</p>
</blockquote>
<p>This is a significant amount of output, so it is not a recommended way of examining the environment.</p>
<p>The <code>'-k'</code> option performs the following function (again a quote):</p>
<blockquote>
<p>All arguments in the form of assignment statements are placed in the environment for a command, not just those that precede the command name.</p>
</blockquote>
<h4 id="example-using-set--k">Example: using <code>set -k</code></h4>
<p>What this means is actually quite simple. The following example demonstrates what setting <code>'-k'</code> does. The script <code>bash21_ex1.sh</code> is fairly simple:</p>
<pre><code>#!/usr/bin/env bash
#-------------------------------------------------------------------------------
# Example 1 for Bash Tips show 21: the environment
#-------------------------------------------------------------------------------
# Not expected to be in the environment
bt211C=somedata
echo &quot;Args: $*&quot;
printenv
exit</code></pre>
<p>Im calling the variables associated with this script <code>'bt211[ABC]'</code> so they are easier to find in the environment listing. To prove that defining variables in the script does not affect the environment we define one (<code>bt211C</code>) for later examination. We then echo any arguments given to the script. Finally we use <code>printenv</code> to show the environment.</p>
<p>Running this script like this results in:</p>
<pre><code>$ set -k
$ bt211A=42 ./bash21_ex1.sh arg1 arg2 bt211B=99 | grep -E &#39;^(Args|bt211)&#39;
Args: arg1 arg2
bt211B=99
bt211A=42</code></pre>
<p>What is happening here:</p>
<ol type="1">
<li>We set the option on with <code>set -k</code></li>
<li>We invoke the script <code>bash21_ex1.sh</code> preceded by <code>bt211A=42</code> which will cause an environment variable of that name to be created in the process that is initiated</li>
<li>We give the script two arguments <code>arg1</code> and <code>arg2</code> and we add in another variable assignment <code>bt211B=99</code>. This should be placed in the environment now that <code>set -k</code> is enabled; if it werent then this string would just be treated as an argument</li>
<li>The output from the script (arguments and data from <code>printenv</code>) is piped through <code>grep</code> which selects anything that starts with <code>'Args'</code> or <code>'bt211'</code></li>
<li>We see the two arguments echoed by the script and the two environment variables - the other variable <code>bt211C</code> is not shown because it is not an environment variable.</li>
</ol>
<p>As with all of the single-letter options to <code>set</code> this one can be turned off again with <code>'set +k'</code> (a little counter-intuitive, but thats how it works).</p>
<h3 id="using-environment-variables">Using environment variables</h3>
<p>You will probably have seen references to environment variables when reading man pages. We have already seen how <code>awk</code> (<code>gawk</code>) can be made to behave differently when given certain variables such as <code>AWKPATH</code>. The same applies to a number of commands, and there is often a section describing such variables in the man page for the command.</p>
<p>Many commands depend on configuration files rather than environment variables nowadays, though it is not uncommon to see environment variables being used as a way to indicate a non-standard location for the configuration files. For example, the GNU Privacy Guard <code>gpg</code> command uses <code>GNUPGHOME</code> to specify a directory to be used instead of the default <code>'~/.gnupg'</code>. Also with the command-line tool for the PostgreSQL database, <code>psql</code>, there are several environment variables that can be set to provide defaults if necessary, for example: <code>PGDATABASE</code>, <code>PGHOST</code>, <code>PGPORT</code> and <code>PGUSER</code>.</p>
<p>In general environment variables are used:</p>
<ol type="1">
<li><p>To pass information about the login environment, such as the particular shell, the desktop and the user. For example, <code>'SHELL'</code> contains the current shell (such as <code>/bin/bash</code>), <code>'DESKTOP_SESSION'</code> defines the chosen desktop environment (such as <code>xfce</code>) and <code>'USER'</code> defines the current username. These values are created during login and can be controlled where appropriate by the shells configuration files.</p></li>
<li><p>To pass relevant information to scripts, commands and programs. These variables can be set in the shells configuration file(s) or on the command line, either temporarily or permanently. We have seen the ways we can set environment variables permanently and temporarily.</p></li>
</ol>
<p>However, it can be argued that any complex software system is better controlled through configuration files than through environment variables. It is common to see the YAML or JSON formats being used to set up configuration files, as well as other file formats. This method allows many settings to be controlled in one place, whereas using environment variables would require many separate variable definitions. On the other hand, environment variables are simpler to manage than having to deal with YAML or JSON formats.</p>
<h2 id="examples">Examples</h2>
<h3 id="various-ways-of-displaying-the-environment">Various ways of displaying the environment</h3>
<pre><code>#!/usr/bin/env bash
#-------------------------------------------------------------------------------
# Example 2 for Bash Tips show 21: the environment
#-------------------------------------------------------------------------------
BTversion=&#39;21&#39;
export BTversion
echo &quot;** Using &#39;grep&#39; with &#39;env&#39;&quot;
env | grep -E &#39;(EDITOR|SHELL|BTversion)=&#39;
echo
echo &quot;** Using &#39;printenv&#39; with arguments&quot;
printenv EDITOR SHELL BTversion
echo
echo &quot;** Using &#39;grep&#39; with &#39;export&#39;&quot;
export | grep -E &#39;(EDITOR|SHELL|BTversion)=&#39;
echo
echo &quot;** Using &#39;grep&#39; with &#39;declare&#39;&quot;
declare -x | grep -E &#39;(EDITOR|SHELL|BTversion)=&#39;
exit</code></pre>
<p>Running the script (<code>bash21_ex2.sh</code>) generates the following output:</p>
<pre><code>** Using &#39;grep&#39; with &#39;env&#39;
SHELL=/bin/bash
EDITOR=/usr/bin/vim
BTversion=21
** Using &#39;printenv&#39; with arguments
/usr/bin/vim
/bin/bash
21
** Using &#39;grep&#39; with &#39;export&#39;
declare -x BTversion=&quot;21&quot;
declare -x EDITOR=&quot;/usr/bin/vim&quot;
declare -x SHELL=&quot;/bin/bash&quot;
** Using &#39;grep&#39; with &#39;declare&#39;
declare -x BTversion=&quot;21&quot;
declare -x EDITOR=&quot;/usr/bin/vim&quot;
declare -x SHELL=&quot;/bin/bash&quot;
</code></pre>
<p>This example shows how environment variable values can be examined with <code>env</code>, <code>printenv</code>, <code>export</code> and <code>declare</code>. I will leave you to investigate <code>set</code> if you wish, though its not the ideal way to find such information.</p>
<h3 id="accessing-the-environment-in-an-awk-script">Accessing the environment in an <code>awk</code> script</h3>
<pre><code>#!/usr/bin/awk -f
#-------------------------------------------------------------------------------
# Example 3 for Bash Tips show 21: printing the environment in Awk
#-------------------------------------------------------------------------------
BEGIN{
for (n in ENVIRON)
printf &quot;ENVIRON[%s]=%s\n&quot;,n,ENVIRON[n]
}</code></pre>
<p>Running the script (<code>bash21_ex3.awk</code>) generates the following output in my particular case:</p>
<pre><code>$ ./bash21_ex3.awk
ENVIRON[AWKPATH]=.:/usr/share/awk
ENVIRON[OLDPWD]=/home/hprdemo
ENVIRON[XDG_SESSION_CLASS]=user
ENVIRON[AWKLIBPATH]=/usr/lib/x86_64-linux-gnu/gawk
ENVIRON[LANG]=en_GB.UTF-8
ENVIRON[XDG_RUNTIME_DIR]=/run/user/1001
ENVIRON[USER]=hprdemo
ENVIRON[LANGUAGE]=en_GB:en
ENVIRON[_]=./bash21_ex3.awk
ENVIRON[SHELL]=/bin/bash
ENVIRON[XDG_SESSION_ID]=57
ENVIRON[SSH_CONNECTION]=::1 55674 ::1 22
ENVIRON[PATH]=/usr/local/bin:/usr/bin:/bin:/usr/games
ENVIRON[SSH_CLIENT]=::1 55674 22
ENVIRON[HOME]=/home/hprdemo
ENVIRON[PWD]=/home/hprdemo/BashTips
ENVIRON[SHLVL]=1
ENVIRON[XDG_SESSION_TYPE]=tty
ENVIRON[LOGNAME]=hprdemo
</code></pre>
<p>If you were to run the above script yourself you would see different values (!) and very likely a lot more of them.</p>
<p><small> <b>Nerdy digression! Ignore if not interested!</b> The way I demonstrate scripts for HPR shows is complicated since I usually run the scripts from the notes while they are being rendered to be sure that the output I show is really correct! This one was actually run over <code>ssh</code> under the local user <code>hprdemo</code>, which has been tailored for such demonstrations, so the environment is not typical. </small></p>
<h3 id="passing-temporary-environment-variables">Passing temporary environment variables</h3>
<pre><code>#!/usr/bin/env bash
#-------------------------------------------------------------------------------
# Example 4 for Bash Tips show 21: a way of showing environment variables
#-------------------------------------------------------------------------------
#
# We expect one or more arguments
#
if [[ $# = 0 ]]; then
echo &quot;Usage: $0 variable_name&quot;
exit 1
fi
#
# Loop through the arguments reporting their attributes with &#39;declare&#39;
#
for arg; do
declare -p &quot;$arg&quot;
done
exit</code></pre>
<p>This simple script (<code>bash21_ex4.sh</code>) allows the demonstration of the existence of selected variables in the environment. First we look at the <code>SHELL</code> variable, managed by Bash:</p>
<pre><code>$ ./bash21_ex4.sh SHELL
declare -x SHELL=&quot;/bin/bash&quot;
</code></pre>
<p>Now we generate our own temporary environment variables and report them:</p>
<pre><code>$ compass=north weather=wet ./bash21_ex4.sh compass weather
declare -x compass=&quot;north&quot;
declare -x weather=&quot;wet&quot;
</code></pre>
<h3 id="using-export-in-bash-configuration-files">Using <code>export</code> in Bash configuration files</h3>
<p>We will be looking at the configuration files that can be used to control your instance of Bash in a later show. The following example (<code>bash21_ex5.sh</code>) shows some of the environment variables I have defined in mine:</p>
<pre><code>#-------------------------------------------------------------------------------
# Example 5 for Bash Tips show 21: a few things exported in my .bashrc
#-------------------------------------------------------------------------------
#
# The PATH variable gets my local ~/bin directory added to it
#
export PATH=&quot;${PATH}:$HOME/bin&quot;
#
# The above is the older way of doing this. It is possible to write the
# following using &#39;+=&#39; to concatenate a string onto a variable:
# export PATH+=&quot;:$HOME/bin&quot;
#
# Some tools need a default editor. The only one for me is Vim
#
export EDITOR=/usr/bin/vim
export VISUAL=/usr/bin/vim
</code></pre>
<h3 id="a-simple-configuration-file-for-a-bash-script">A simple configuration file for a Bash script</h3>
<p><b>Note</b>: the following example is quite detailed and somewhat convoluted. You might prefer to skip it; you will probably not lose much by doing so!</p>
<p>In the script I use to manage episodes I submit to HPR I use a simple configuration file. The script was begun in 2013 and was intended to be entirely implemented in Bash. At that time I came up with the idea of creating a file of <code>export</code> commands to define a collection of variables. The following is an example called <code>bash21_ex6_1.cfg</code> which contains settings for this episode of <em>Bash Tips</em> (slightly edited):</p>
<pre><code>export _CFG_PROJECT=&quot;Bash_Tips__21&quot;
export _CFG_HOSTID=225
export _CFG_HOSTNAME=&quot;Dave Morriss&quot;
export _CFG_SUMMARY=&quot;Environment variables&quot;
export _CFG_TAGS=&quot;Bash,variable,environment&quot;
export _CFG_EXPLICIT=&quot;Yes&quot;
export _CFG_FILES=(hpr____.html hpr____.tbz)
export _CFG_STRUCTURE=&quot;Tree&quot;
export _CFG_SERIES=&quot;Bash Scripting&quot;
export _CFG_NOTETYPE=&quot;HTML&quot;
export _CFG_SUMADDED=&quot;No&quot;
export _CFG_INOUT=&quot;No&quot;
export _CFG_EMAIL=&quot;blah@blah&quot;
export _CFG_TITLE=&quot;Bash Tips - 21&quot;
export _CFG_STATUS=&quot;Editing&quot;
export _CFG_SLOT=&quot;&quot;
</code></pre>
<p>This idea works in a limited way. Using the <code>'source'</code> command on the file will cause all of the <code>export</code> statements to be obeyed and the variables will be placed in the environment. There is one exception though; the definition of <code>'_CFG_FILES'</code> does not result in an environment variable because its an array and Bash does not support arrays in the environment. However, an array <em>is</em> created as an ordinary variable.</p>
<p>Originally I expected that I would need to access these environment variables in sub-processes or using Awk or Perl scripts. In the latter two cases the variables <em>must</em> be in the environment, but I found I didnt need to do this in fact.</p>
<p>The demonstration script <code>bash21_ex6.sh</code> takes these variables and generates a new configuration file from them using <code>declare</code> statements:</p>
<pre><code>#!/usr/bin/env bash
#-------------------------------------------------------------------------------
# Example 6 for Bash Tips show 21: a poor way to make a configuration file
#-------------------------------------------------------------------------------
#
# Example configuration file using &#39;export&#39;
#
CFG1=&#39;bash21_ex6_1.cfg&#39;
if [[ ! -e $CFG1 ]]; then
echo &quot;Unable to find $CFG1&quot;
exit 1
fi
#
# Alternative configuration file using &#39;declare&#39;, converted from the other one
#
CFG2=&#39;bash21_ex6_2.cfg&#39;
#
# Strip out all of the &#39;export&#39; commands with &#39;sed&#39; in a process substitution,
# turning the lines into simple variable declarations. Use &#39;source&#39; to obey
# all of the resulting commands
#
source &lt;(sed &#39;s/^export //&#39; $CFG1)
#
# Scan the (simple) variables beginning with &#39;_CFG_&#39; and convert them into
# a portable form by saving the output of &#39;declare -p&#39;
#
declare -p &quot;${!_CFG_@}&quot; &gt; $CFG2
#
# Now next time we can &#39;source&#39; this file instead when we want the variables
#
cat $CFG2
exit</code></pre>
<p>The variable <code>'CFG1'</code> contains the name of the file of <code>export</code> commands, <code>bash21_ex6_1.cfg</code>. Rather than placing all of these variables into the environment the script strips the <code>'export'</code> string from each line, making them simple assignments. The result is processed using the <code>source</code> command, taking its input from a process substitution running <code>'sed'</code>, and then the second configuration file is created, <code>bash21_ex6_2.cfg</code>.</p>
<p>The <code>declare</code> command needs explanation:</p>
<pre><code>declare -p &quot;${!_CFG_@}&quot; &gt; $CFG2
</code></pre>
<p>It uses <code>'declare -p'</code> to print out <code>declare</code> statements, redirecting them to the new configuration file whose name is in variable <code>'CFG2'</code>. The expression used to find all the variables: <code>"${!_CFG_@}"</code> uses a Bash parameter expansion feature which we looked at back in HPR episode 1648. It returns the names of all variables whose names begin with <code>'_CFG_'</code>. The expression ends with <code>'@'</code> which (like when expanding arrays) causes a list of distinct arguments to be generated rather than one single long string.</p>
<p>The script lists the contents of the file <code>bash21_ex6_2.cfg</code> to demonstrate what has happened.</p>
<p>Running this script results in the following:</p>
<pre><code>$ ./bash21_ex6.sh
declare -- _CFG_EMAIL=&quot;blah@blah&quot;
declare -- _CFG_EXPLICIT=&quot;Yes&quot;
declare -a _CFG_FILES=([0]=&quot;hpr____.html&quot; [1]=&quot;hpr____.tbz&quot;)
declare -- _CFG_HOSTID=&quot;225&quot;
declare -- _CFG_HOSTNAME=&quot;Dave Morriss&quot;
declare -- _CFG_INOUT=&quot;No&quot;
declare -- _CFG_NOTETYPE=&quot;HTML&quot;
declare -- _CFG_PROJECT=&quot;Bash_Tips__21&quot;
declare -- _CFG_SERIES=&quot;Bash Scripting&quot;
declare -- _CFG_SLOT=&quot;&quot;
declare -- _CFG_STATUS=&quot;Editing&quot;
declare -- _CFG_STRUCTURE=&quot;Tree&quot;
declare -- _CFG_SUMADDED=&quot;No&quot;
declare -- _CFG_SUMMARY=&quot;Environment variables&quot;
declare -- _CFG_TAGS=&quot;Bash,variable,environment&quot;
declare -- _CFG_TITLE=&quot;Bash Tips - 21&quot;
</code></pre>
<p>Note how nothing is marked with <code>'-x'</code> because they had not been exported to the environment, especially the array (which cant be!). Note that the array has been handled properly by <code>'declare -p'</code> and the output file could be used to backup and restore this array. This is a safer format than the original file of assignments.</p>
<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 <a href="https://www.gnu.org/software/bash/manual/bash.html#Command-Execution-Environment">“3.7.3 Command Execution Environment”</a></li>
<li>Section <a href="https://www.gnu.org/software/bash/manual/bash.html#Environment">“3.7.4 Environment”</a></li>
</ul></li>
<li><a href="https://www.gnu.org/software/coreutils/manual/"><em>GNU Coreutils Manual</em></a>
<ul>
<li>Section <a href="https://www.gnu.org/software/coreutils/manual/html_node/env-invocation.html">23.2 env: Run a command in a modified environment</a></li>
</ul></li>
<li><p><a href="https://en.wikipedia.org/wiki/Env">Wikipedia page on the <code>env</code> command</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>:<br />
<small><strong>Episode number</strong></small>
<ol>
<li><a href="https://hackerpublicradio.org/eps/hpr1648">HPR episode 1648 <code>"</code><em>Bash parameter manipulation</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr1843">HPR episode 1843 <code>"</code><em>Some Bash tips</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr1884">HPR episode 1884 <code>"</code><em>Some more Bash tips</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr1903">HPR episode 1903 <code>"</code><em>Some further Bash tips</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr1951">HPR episode 1951 <code>"</code><em>Some additional Bash tips</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2045">HPR episode 2045 <code>"</code><em>Some other Bash tips</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2278">HPR episode 2278 <code>"</code><em>Some supplementary Bash tips</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2293">HPR episode 2293 <code>"</code><em>More supplementary Bash tips</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2639">HPR episode 2639 <code>"</code><em>Some ancillary Bash tips - 9</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2649">HPR episode 2649 <code>"</code><em>More ancillary Bash tips - 10</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2659">HPR episode 2659 <code>"</code><em>Further ancillary Bash tips - 11</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2669">HPR episode 2669 <code>"</code><em>Additional ancillary Bash tips - 12</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2679">HPR episode 2679 <code>"</code><em>Extra ancillary Bash tips - 13</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2689">HPR episode 2689 <code>"</code><em>Bash Tips - 14 (Some auxiliary Bash tips)</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2699">HPR episode 2699 <code>"</code><em>Bash Tips - 15 (More auxiliary Bash tips)</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2709">HPR episode 2709 <code>"</code><em>Bash Tips - 16 (Further auxiliary Bash tips)</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2719">HPR episode 2719 <code>"</code><em>Bash Tips - 17 (Additional auxiliary Bash tips)</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2729">HPR episode 2729 <code>"</code><em>Bash Tips - 18 (Extra auxiliary Bash tips)</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2739">HPR episode 2739 <code>"</code><em>Bash Tips - 19 (Supplemental auxiliary Bash tips)</em><code>"</code></a></li>
<li><a href="https://hackerpublicradio.org/eps/hpr2756">HPR episode 2756 <code>"</code><em>Bash Tips - 20 (Some collateral Bash tips)</em><code>"</code></a></li>
</ol></li>
</ul>
<!--- -->
<ul>
<li>Resources:
<ul>
<li>Examples:
<ul>
<li><a href="hpr3013_bash21_ex1.sh">bash21_ex1.sh</a></li>
<li><a href="hpr3013_bash21_ex2.sh">bash21_ex2.sh</a></li>
<li><a href="hpr3013_bash21_ex3.awk">bash21_ex3.awk</a></li>
<li><a href="hpr3013_bash21_ex4.sh">bash21_ex4.sh</a></li>
<li><a href="hpr3013_bash21_ex5.sh">bash21_ex5.sh</a></li>
<li><a href="hpr3013_bash21_ex6.sh">bash21_ex6.sh</a></li>
<li><a href="hpr3013_bash21_ex6_1.cfg">bash21_ex6_1.cfg</a></li>
<li><a href="hpr3013_bash21_ex6_2.cfg">bash21_ex6_2.cfg</a></li>
</ul></li>
</ul></li>
</ul>
</article>
</main>
</div>
</body>
</html>