Bash Shell Script Variable Assignment

Variables!

Temporary stores of information

Introduction

For those of you that have dabbled in programming before, you'll be quite familiar with variables. For those of you that haven't, think of a variable as a temporary store for a simple piece of information. These variables can be very useful for allowing us to manage and control the actions of our Bash Script. We'll go through a variety of different ways that variables have their data set and ways we can then use them.

Variables are one of those things that are actually quite easy to use but are also quite easy to get yourself into trouble with if you don't properly understand how they work. As such there is a bit of reading in this section but if you take the time to go through and understand it you will be thankful you did later on when we start dabbling in more complex scripts.

How do they Work?

A variable is a temporary store for a piece of information. There are two actions we may perform for variables:

  • Setting a value for a variable.
  • Reading the value for a variable.

Variables may have their value set in a few different ways. The most common are to set the value directly and for its value to be set as the result of processing by a command or program. You will see examples of both below.

To read the variable we then place its name (preceded by a $ sign) anywhere in the script we would like. Before Bash interprets (or runs) every line of our script it first checks to see if any variable names are present. For every variable it has identified, it replaces the variable name with its value. Then it runs that line of code and begins the process again on the next line.

Here are a few quick points on syntax. They will be elaborated on and demonstrated as we go into more detail below.

  • When referring to or reading a variable we place a $ sign before the variable name.
  • When setting a variable we leave out the $ sign.
  • Some people like to always write variable names in uppercase so they stand out. It's your preference however. They can be all uppercase, all lowercase, or a mixture.
  • A variable may be placed anywhere in a script (or on the command line for that matter) and, when run, Bash will replace it with the value of the variable. This is made possible as the substitution is done before the command is run.

Command line arguments

Command line arguments are commonly used and easy to work with so they are a good place to start.

When we run a program on the command line you would be familiar with supplying arguments after it to control its behaviour. For instance we could run the command ls -l /etc. -l and /etc are both command line arguments to the command ls. We can do similar with our bash scripts. To do this we use the variables $1 to represent the first command line argument, $2 to represent the second command line argument and so on. These are automatically set by the system when we run our script so all we need to do is refer to them.

Let's look at an example.

mycopy.sh

  1. #!/bin/bash
  2. cp $1 $2
  3. echo Details for $2
  4. ls -lh $2

Let's break it down:

  • Line 4 - run the command cp with the first command line argument as the source and the second command line argument as the destination.
  • Line 8 - run the command echo to print a message.
  • Line 9 - After the copy has completed, run the command ls for the destination just to verify it worked. We have included the options l to show us extra information and h to make the size human readable so we may verify it copied correctly.
  1. ./mycopy.sh /projects/file1.data ./results.data
  2. Details for ./results.data
  3. -rw-r--r-- 18 ryan users 3.4M Feb 14 07:18 results.data

We'll discuss their usage a little more in the next section ( 3. Input ).

Other Special Variables

There are a few other variables that the system sets for you to use as well.

  • $0 - The name of the Bash script.
  • $1 - $9 - The first 9 arguments to the Bash script. (As mentioned above.)
  • $# - How many arguments were passed to the Bash script.
  • $@ - All the arguments supplied to the Bash script.
  • $? - The exit status of the most recently run process.
  • $$ - The process ID of the current script.
  • $USER - The username of the user running the script.
  • $HOSTNAME - The hostname of the machine the script is running on.
  • $SECONDS - The number of seconds since the script was started.
  • $RANDOM - Returns a different random number each time is it referred to.
  • $LINENO - Returns the current line number in the Bash script.

If you type the command env on the command line you will see a listing of other variables which you may also refer to.

Some of these variables may seem useful to you now. Others may not. As we progress to more complex scripts in later sections you will see examples of how they can be useful.

Setting Our Own Variables

As well as variables that are preset by the system, we may also set our own variables. This can be useful for keeping track of results of commands and being able to refer to and process them later.

There are a few ways in which variables may be set (such as part of the execution of a command) but the basic form follows this pattern:

variable=value

This is one of those areas where formatting is important. Note there is no space on either side of the equals ( = ) sign. We also leave off the $ sign from the beginning of the variable name when setting it.

Variable names may be uppercase or lowercase or a mixture of both but Bash is a case sensitive environment so whenever you refer to a variable you must be consistent in your use of uppercase and lowercase letters. You should always make sure variable names are descriptive. This makes their purpose easier for you to remember.

Here is a simple example to illustrate their usage.

simplevariables.sh

  1. #!/bin/bash
  2. myvariable=Hello
  3. anothervar=Fred
  4. echo $myvariable $anothervar
  5. echo
  6. sampledir=/etc
  7. ls $sampledir

Let's break it down:

  • Lines 4 and 6 - set the value of the two variables myvariable and anothervar.
  • Line 8 - run the command echo to check the variables have been set as intended.
  • Line 9 - run the command echo this time with no arguments. This is a good way to get a blank line on the screen to help space things out.
  • Line 11 - set another variable, this time as the path to a particular directory.
  • Line 13 - run the command ls substituting the value of the variable sampledir as its first command line argument.
  1. ./simplevariables.sh
  2. Hello Fred
  3. a2ps.cfg aliases alsa.d ...

It is important to note that in the example above we used the command echo simply because it is a convenient way to demonstrate that the variables have actually been set. echo is not needed to make use of variables and is only used when you wish to print a specific message to the screen. (Pretty much all commands print output to the screen as default so you don't need to put echo in front of them.)

Variables can be useful for making our scripts easier to manage. Maybe our script is going to run several commands, several of which will refer to a particular directory. Rather than type that directory out each time we can set it once in a variable then refer to that variable. Then if the required directory changes in the future we only need to update one variable rather than every instance within the script.

Quotes

In the example above we kept things nice and simple. The variables only had to store a single word. When we want variables to store more complex values however, we need to make use of quotes. This is because under normal circumstances Bash uses a space to determine separate items.

  1. myvar=Hello World
  2. -bash: World: command not found
  • Remember, commands work exactly the same on the command line as they do within a script.

Because commands work exactly the same on the command line as in a script it can sometimes be easier to experiment on the command line.

When we enclose our content in quotes we are indicating to Bash that the contents should be considered as a single item. You may use single quotes ( ' ) or double quotes ( " ).

  • Single quotes will treat every character literally.
  • Double quotes will allow you to do substitution (that is include variables within the setting of the value).
  1. myvar='Hello World'
  2. echo $myvar
  3. Hello World
  4. newvar="More $myvar"
  5. echo $newvar
  6. More Hello World
  7. newvar='More $myvar'
  8. echo $newvar
  9. More $myvar

Command Substitution

Command substitution allows us to take the output of a command or program (what would normally be printed to the screen) and save it as the value of a variable. To do this we place it within brackets, preceded by a $ sign.

  1. myvar=$( ls /etc | wc -l )
  2. echo There are $myvar entries in the directory /etc

Command substitution is nice and simple if the output of the command is a single word or line. If the output goes over several lines then the newlines are simply removed and all the output ends up on a single line.

  1. ls
  2. bin Documents Desktop ...
  3. Downloads public_html ...
  4. myvar=$( ls )
  5. echo $myvar
  6. bin Documents Desktop Downloads public_html ...

Let's break it down:

  • Line 1 - We run the command ls. Normally its output would be over several lines. I have shortened it a bit in the example above just to save space.
  • Line 4 - When we save the command to the variable myvar all the newlines are stripped out and the output is now all on a single line.

When playing about with command substitution it's a good idea to test your output rather than just assuming it will behave in a certain way. The easiest way to do that is simply to echo the variable and see what has happened. (You can then remove the echo command once you are happy.)

Exporting Variables

Remember how in the previous section we talked about scripts being run in their own process? This introduces a phenomenon known as scope which affects variables amongst other things. The idea is that variables are limited to the process they were created in. Normaly this isn't an issue but sometimes, for instance, a script may run another script as one of its commands. If we want the variable to be available to the second script then we need to export the variable.

script1.sh

  1. #!/bin/bash
  2. var1=blah
  3. var2=foo
  4. echo $0 :: var1 : $var1, var2 : $var2
  5. export var1
  6. ./script2.sh
  7. echo $0 :: var1 : $var1, var2 : $var2

script2.sh

  1. #!/bin/bash
  2. echo $0 :: var1 : $var1, var2 : $var2
  3. var1=flop
  4. var2=bleh

Now lets run it and see what happens.

  1. ./script1.sh
  2. script1.sh :: var1 : blah, var2 : foo
  3. script2.sh :: var1 : blah, var2 :
  4. script1.sh :: var1 : blah, var2 : foo

The output above may seem unexpected. What actually happens when we export a variable is that we are telling Bash that every time a new process is created (to run another script or such) then make a copy of the variable and hand it over to the new process. So although the variables will have the same name they exist in separate processes and so are unrelated to each other.

Exporting variables is a one way process. The original process may pass variables over to the new process but anything that process does with the copy of the variables has no impact on the original variables.

Exporting variables is something you probably won't need to worry about for most Bash scripts you'll create. Sometimes you may wish to break a particular task down into several separate scripts however to make it easier to manage or to allow for reusability (which is always good). For instance you could create a script which will make a dated (ie todays date prepended to the filename) copy of all filenames exported on a certain variable. Then you could easily call that script from within other scripts you create whenever you would like to take a snapshot of a set of files.

Summary

$1, $2, ...
The first, second, etc command line arguments to the script.
variable=value
To set a value for a variable. Remember, no spaces on either side of =
Quotes " '
Double will do variable substitution, single will not.
variable=$( command )
Save the output of a command into a variable
export var1
Make the variable var1 available to child processes.
Formatting
The presence or absence of spaces is important.
Manageability
If a particular value is used several times within a script (eg a file or directory name) then using a variable can make it easier to manage.

Activities

Let's explore variables.

  • A good place to start is to create a simple script which will accept some command line arguments and echo out some details about them (eg, how many are there, what is the secone one etc).
  • Create a script which will print a random word. There is a file containing a list of words on your system (usually /usr/share/dict/words or /usr/dict/words). Hint: Piping will be useful here.
  • Expand the previous activity so that if a number is supplied as the first command line argument then it will select from only words with that many characters. Hint: Grep may be useful here.
  • Take a copy of the two files script1.sh and script2.sh above then experiment by tweaking them and running them and observing the output. This will help you get a feel for how exporting variables works.
  • Now let's create a script which will take a filename as its first argument and create a dated copy of the file. eg. if our file was named file1.txt it would create a copy such as 2018-03-11_file1.txt. (To achieve this you will probably want to play with command substitution and the command date)
  • Challenge: To make it a bit harder, see if you can get it so that the date is after the name of the file (eg. file1_2018-03-11.txt (The command basename can be useful here.)
  • Challenge: Now see if you can expand the previous question to accept a list of files on the command line and it will create a named copy of all of them. (The command xargs may be useful here.)

NextPrevious

Shell Script Basics

Writing a shell script is like riding a bike. You fall off and scrape your knees a lot at first. With a bit more experience, you become comfortable riding them around town, but also quickly discover why most people drive cars for longer trips.

Shell scripting is generally considered to be a glue language, ideal for creating small pieces of code that connect other tools together. While shell scripts can be used for more complex tasks, they are usually not the best choice.

If you have ever successfully trued a bicycle wheel (or paid someone else to do so), that’s similar to learning the basics of shell scripting. If you don’t true your scripts, they wobble. Put another way, it is often easy to write a script, but it can be more challenging to write a script that consistently works well.

This chapter and the next two chapters introduce the basic concepts of shell scripting. The remaining chapters in this document provide additional breadth and depth. This document is not intended to be a complete reference on writing shell scripts, nor could it be. It does, however, provide a good starting point for beginners first learning this black art.

Shell Script Dialects

There are many different dialects of shell scripts, each with their own quirks, and some with their own syntax entirely. Because of these differences, the road to good shell scripting can be fraught with peril, leading to script failures, misbehavior, and even outright data loss.

To that end, the first lesson you must learn before writing a shell script is that there are two fundamentally different sets of shell script syntax: the Bourne shell syntax and the C shell syntax. The C shell syntax is more comfortable to many C programmers because the syntax is somewhat similar. However, the Bourne shell syntax is significantly more flexible and thus more widely used. For this reason, this document only covers the Bourne shell syntax.

The second hard lesson you will invariably learn is that each dialect of Bourne shell syntax differs slightly. This document includes only pure Bourne shell syntax and a few BASH-specific extensions. Where BASH-specific syntax is used, it is clearly noted.

The terminology and subtle syntactic differences can be confusing—even a bit overwhelming at times; had Dorothy in The Wizard of Oz been a programmer, you might have heard her exclaim, "BASH and ZSH and CSH, Oh My!" Fortunately, once you get the basics, things generally fall into place as long as you avoid using shell-specific features. Stay on the narrow road and your code will be portable.

Some common shells are listed below, grouped by script syntax:

Bourne-compatible shells

C-shell-compatible shells

  • (C shell to Bourne shell translator/emulator)

Many of these shells have more than one variation. Most of these variations are denoted by prefixing the name of an existing shell with additional letters that are short for whatever differentiates them from the original shell. For example:

  • The shell is a variant of . Being a public domain rewrite of AT&T's , it stands for "Public Domain Korn SHell." (This is a bit of a misnomer, as a few bits are under a BSD-like open source license. However, the name remains.)

  • The shell is an extension of . It stands for the TENEX C SHell, as some of its enhancements were inspired by the TENEX operating system.

  • The shell is an extension of . It stands for the Bourne Again SHell. (Oddly enough, it is not a variation of , the Almquist SHell, though both are Bourne shell variants. This should not be confused with the shell—an -derived shell used in some Linux distributions—whose name stands for the Debian Almquist SHell.)

And so on. In general, with the exception of and , it is usually safe to assume that any modern login shell is compatible with Bourne shell syntax.

Note: Because the C shell syntax is not well suited to scripting beyond a very basic level, this document does not cover C shell variants in depth. For more information, see She Sells C Shells.

She Sells C Shells

The C shell is popular among some users as a shell for interacting with the computer because it allows simple scripts to be written more easily. However, the C shell scripting language is limited in a number of ways, many of which are hard to work around. For this reason, use of the C shell scripting language for writing complex scripts is not recommended. For more information, read “CSH Programming Considered Harmful” at http://www.faqs.org/faqs/unix-faq/shell/csh-whynot/. Although many of the language flaws it describes are fixed by some modern C shells, if you are writing a script that must work on multiple computers across different operating systems, you cannot always guarantee that the installed C shell will support those extensions.

However, the C shell scripting language has its uses, particularly for writing scripts that set up environment variables for interactive shell environments, execute a handful of commands in order, or perform other relatively lightweight chores. To support such uses, the C shell syntax is presented alongside the Bourne shell syntax within this "basics” chapter where possible.

Outside of this chapter, this document does not generally cover the C shell syntax. If after reading this, you still want to write a more complex script using the C shell programming language, you can find more information in on the C shell in the manual page for .

Shell Variables and Printing

What follows is a very basic shell script that prints “Hello, world!” to the screen:

#!/bin/sh
echo "Hello, world!"

The first thing you should notice is that the script starts with ‘’. This is known as an interpreter line. If you don’t specify an interpreter line, the default is usually the Bourne shell (). However, it is best to specify this line anyway for consistency.

The second thing you should notice is the command. The command is nearly universal in shell scripting as a means for printing something to the user’s screen. (Technically speaking, is generally a shell builtin, but it also exists as as standalone command, . You can read more about the difference between the builtin version and the standalone version in echo and Use Shell Builtins Wherever Possible.)

If you’d like, you can try this script by saving those lines in a text file (say “hello_world.sh”) in your home directory. Then, in Terminal, type:

chmod u+x hello_world.sh
./hello_world.sh

Of course, this script isn’t particularly useful. It just prints the words “Hello, world!“ to your screen. To make this more interesting, the next script throws in a few variables.

#!/bin/sh
FIRST_ARGUMENT="$1"
echo "Hello, world $FIRST_ARGUMENT!"

Type or paste this script into the text editor of your choice (see Creating Text Files in Your Home Directory for help creating a text file) and save the file in your home directory in a file called .

Once you have saved the file in your home directory, type ‘’ in Terminal to make it executable. Finally, run it with ‘’. You should see “Hello, world leaders!” printed to your screen.

This script provides an example of a variable assignment. The variable contains the first argument passed to the shell script. In this example, the script makes a copy and stores it into a variable called , then prints that variable.

You should immediately notice that variables may or may not begin with a dollar sign, depending on how you are using them. If you want to dereference a variable, you precede it with a dollar sign. The shell then inserts the contents of the variable at that point in the script. For all other uses, you do not precede it with a dollar sign.

Important: You generally do not want to prefix the variable on the left side of an assignment statement with a dollar sign. Because starts out empty, if you used a dollar sign, the first line:

$FIRST_ARGUMENT="$1" # DO NOT DO THIS!
would be expanded by the shell into the following complete gibberish:
="myfirstcommandlineargument"
This is clearly not what you want (and produces an error). Because of the order in which the statement is evaluated, the above assignment statement would still fail with an error even if were nonempty. (If you really want to assign a value to a variable whose name is in a different variable, use , as described in Using the eval Builtin for Data Structures, Arrays, and Indirection.)

You should also notice that the argument to echo is surrounded by double quotation marks. This is explained further in the next section, Using Arguments And Variables That Contain Spaces.

C Shell Note: The syntax for assignment statements in the C shell is rather different. Instead of an assignment statement, the C shell uses the and builtins to set variables as shown below:

set VALUE = "Four"
# or...
setenv VALUE "Four"
echo "$VALUE score and seven years ago...."
The functional difference between and is described in Exporting Shell Variables.

Using Arguments And Variables That Contain Spaces

Take a second look at the script from the previous section:

#!/bin/sh
FIRST_ARGUMENT="$1"
echo "Hello, world $FIRST_ARGUMENT!"

Notice that the echo statement is followed by a string surrounded by quotation marks. Normally, the shell uses spaces to separate arguments to commands. Outside of quotation marks, the shell would treat “Hello,” and “world” as separate arguments to .

By surrounding the string with double quote marks, the shell treats the entire string as a single argument to even though it contains spaces.

To see how this works, save the script above as (if you haven’t already), then type the following commands:

./test.sh leaders and citizens
./test.sh "leaders and citizens"

The first line above prints “Hello, world leaders!” because the space after “leaders” ends the first argument (). Inside the script, the variable contains “leaders”, contains “and”, and contains “citizens”.

The second line above prints “Hello, world leaders and citizens!” because the quotation marks on the command line cause everything within them to be grouped as a single argument.

Notice also that there are similar quotation marks on the right side of the assignment statement:

With most modern shells, these double quotation marks are not required for this particular assignment statement (because there are no literal spaces on the right side), but they are a good idea for maximum compatibility. See Historical String Parsing in Historical Footnotes and Arcana to learn why.

When assigning literal strings (rather than variables containing strings) to a variable, however, you must surround any spaces with quotation marks. For example, the following statement does not do what you might initially suspect:

If you type this statement, the Bourne shell gives you an error like this:

sh: is: command not found

The reason for this seemingly odd error is that the assignment statement ends at the first space, so the next word after that statement is interpreted as a command to execute. See Overriding Environment Variables for Child Processes (Bourne Shell) for more details.

Instead, write this statement as:

Using quotation marks is particularly important when working with variables that contain filenames or paths. For example, type the following commands:

mkdir "/tmp/My Folder"
FILENAME="/tmp/My Folder"
ls "$FILENAME"
ls $FILENAME

The above example creates a directory in called “My Folder”. (Don’t worry about deleting it because gets wiped every time you reboot.) It then attempts to list the files in that directory. The first time, it uses quotation marks. The second time, it does not. Notice that the shell misinterprets the command the second time as being an attempt to list the files in and the files in .

Handling Quotation Marks in Strings

In modern Bourne shells, expansion of variables, occurs after the statement itself is fully parsed by the shell. (See Historical String Parsing in Historical Footnotes and Arcana for more information.) Thus, as long as the variable is enclosed in double quote marks, you do not get any execution errors even if the variable’s value contains double-quote marks.

However, if you are using double quote marks within a literal string, you must quote that string properly. For example:

MYSTRING="The word of the day is \"sedentary\"."

C Shell Note: The C shell handling of backslashes within double-quoted strings is different. In the C shell, the previous example should be changed to:

MYSTRING="The word of the day is "\""sedentary"\""."
./test.sh \""leaders"\"
to achieve the desired effect. This difference is described further in Parsing, Variable Expansion, and Quoting.

This quoting technique also applies to literal strings within commands entered on the command line. For example, using the script from earlier in Shell Variables and Printing, the command:

prints the phrase “Hello, world “leaders”!”

The details of quotes as they apply to variable expansion are explained in Parsing, Variable Expansion, and Quoting. (Variable safety with shells that predate this behavior is generally impractical. Fortunately, the modern behavior has been the norm since the mid-1990s.)

Shell scripts also allow the use of single quote marks. Variables between single quotes are not replaced by their contents. Be sure to use double quotes unless you are intentionally trying to display the actual name of the variable. You can also use single quotes as a way to avoid the shell interpreting the contents of the string in any way. These differences are described further in Parsing, Variable Expansion, and Quoting.

Exporting Shell Variables

One key feature of shell scripts is that variables are typically limited in their scope to the currently running script. The scoping of variables is described in more detail in Subroutines, Scoping, and Sourcing. For now, though, it suffices to say that variables generally do not get passed on to scripts or tools that they execute.

Normally, this is what you want. Most variables in a shell script do not have any meaning to the tools that they execute, and thus represent clutter and the potential for variable namespace collisions if they are exported. Occasionally, however, you will find it necessary to make a variable's value available to an outside tool. To do this, you must export the variable. These exported variables are commonly known as environment variables because they affect the execution of every script or tool that runs but are not part of those scripts or tools themselves.

A classic example of an environment variable that is significant to scripts and tools is the variable. This variable specifies a list of locations that the shell searches when executing programs by name (without specifying a complete path). For example, when you type on the command line, the shell searches in the locations specified in (in the order specified) until it finds an executable called (or runs out of locations, whichever comes first).

The details of exporting shell variables differ considerably between the Bourne shell and the C shell. Thus, the following sections explain these details in a shell-specific fashion.

Using the export Builtin (Bourne Shell)

Generally speaking, the first time you assign a value to an environment variable such as the variable, the Bourne shell creates a new, local copy of this shell variable that is specific to your script. Any tool executed from your script is passed the original value of inherited from whatever script, tool, or shell that launched it.

With the BASH shell, however, any variable inherited from the environment is automatically exported by the shell. Thus, in some versions of OS X, if you modify inherited environment variables (such as ) in a script, your local changes will be seen automatically by any tool or script that your script executes. Thus, in these versions of OS X, you do not have to explicitly use the statement when modifying the variable.

Because different Bourne shell variants handle these external environment variables differently (even among different versions of OS X), this creates two minor portability problems:

  • A script written without the statement may work on some versions of OS X, but will fail on others. You can solve this portability problem by using the builtin, as described in this section.

  • A shell script that changes variables such as will alter the behavior of any script that it executes, which may or may not be desirable. You can solve this problem by overriding the environment variable when you execute each individual tool, as described in Overriding Environment Variables for Child Processes (Bourne Shell).

To guarantee that your modifications to a shell variable are passed to any script or tool that your shell script calls, you must use the builtin. You do not have to use this command every time you change the value; the variable remains exported until the shell script exits.

For example:

export PATH="/usr/local/bin:$PATH"
# or
PATH="/usr/local/bin:$PATH"
export PATH

Either of these statements has the same effect—specifically, they export the local notion of the environment variable to any command that your script executes from now on. There is a small catch, however. You cannot later undo this export to restore the original global declaration. Thus, if you need to retain the original value, you must store it somewhere yourself.

In the following example, the script stores the original value of the environment variable, exports an altered version, executes a command, and restores the old version.

ORIGPATH="$PATH"
PATH="/usr/local/bin:$PATH"
export PATH
# Execute some command here---perhaps a
# modified ls command....
ls
PATH="$ORIGPATH"

If you need to find out whether an environment variable (whether inherited by your script or explicitly set with the directive) was set to empty or was never set in the first place, you can use the command to obtain a complete list of defined variables and use to see if it is in the list. (You should note that although is a csh builtin, it is also a standalone command in .)

For example:

DEFINED=`printenv | grep -c '^VARIABLE='`

The resulting variable will contain 1 if the variable is defined in the environment or 0 if it is not.

Overriding Environment Variables for Child Processes (Bourne Shell)

Because the BASH Bourne shell variant automatically exports all variables inherited from its environment, any changes you make to preexisting environment variables such as are automatically inherited by any tool or script that your script executes. (This is not true for other Bourne shell variants; see Using the export Builtin (Bourne Shell) for further explanation.)

While automatic export is usually convenient, you may sometimes wish to change a preexisting environment variable without modifying the environment of any script or tool that your script executes. For example, if your script executes a number of tools in , it may be convenient to change the value of to include . However, you may not want child processes to also look in .

This problem is easily solved by overriding the environment variable on a per-execution basis. Consider the following script:

This script prints the value of the variable . Normally, this variable is empty, so this script just prints a blank line. Save the script as , then type the following commands:

chmod a+x printmyvar.sh # makes the script executable
MYVAR=7 ./printmyvar.sh # runs the script
echo "MYVAR IS $MYVAR" # prints the variable

Notice that the assignment statement applies to the command that follows it. The value of is altered in the environment of the command , so the script prints the number 7. However, the original (empty) value is restored after executing that command, so the echo statement afterwards prints an empty string for the value of .

Thus, to modify the variable locally but execute a command with the original value, you can write a script like this:

#!/bin/sh
GLOBAL_PATH="$PATH"
PATH=/usr/local/bin
PATH="$GLOBAL_PATH" /bin/ls

Using the setenv Builtin (C shell)

In the C shell, variables are exported if you set them with , but not if you set them with . Thus, if you want your shell variable modifications to be seen by any tool or script that you call, you should use the builtin. This builtin is the C shell equivalent to issuing an assignment statement with the builtin in the Bourne shell.

setenv VALUE "Four"
echo "VALUE is '$VALUE'."

If you want your shell variables to only be available to your script, you should use the builtin (described in Shell Variables and Printing). The builtin is equivalent to a simple assignment statement in the Bourne shell.

set VALUE = "Four"
echo "VALUE is '$VALUE'."

Notice that the local variable version requires an equals sign (), but the exported environment version does not (and produces an error if you put one in).

To remove variables in the C shell, you can use the or builtin. For example:

setenv VALUE "Four"
unsetenv VALUE
set VALUE = "Four"
unset VALUE
echo "VALUE is '$VALUE'."

This will generate an error message. In the C shell, it is not possible to print the value of an undefined variable, so if you think you may need to print the value later, you should set it to an empty string rather than using or .

If you need to test an environment variable (not a shell-local variable) that may or may not be part of your environment (a variable set by whatever process called your script), you can use the builtin. This prints the value of a variable if set, but prints nothing if the variable is not set, and thus behaves just like the variable behaves in the Bourne shell.

For example:

set X = `printenv VALUE`
echo "X is "\"$X\"

This prints if the variable is either empty or undefined. Otherwise, it prints the value of the variable between the quotation marks.

If you need to find out if a variable is simply empty or is actually not set, you can also use to obtain a complete list of defined variables and use to see if it is in the list. For example:

set DEFINED = `printenv | grep -c '^VARIABLE='`

The resulting variable will contain 1 if the variable is defined in the environment or 0 if it is not.

Overriding Environment Variables for Child Processes (C Shell)

Unlike the Bourne shell, the C shell does not provide a built-in syntax for overriding environment variables when executing external commands. However, it is possible to simulate this either by using the command.

The best and simplest way to do this is with the command. For example:

env PATH="/usr/local/bin" /bin/ls

As an alternative, you can use the builtin to make a temporary copy of any variable you need to override, change the value, execute the command, and restore the value from the temporary copy.

You should notice, however, that whether you use the command or manually make a copy, the variable is altered prior to searching for the command. Because the variable controls where the shell looks for programs to execute, you must therefore explicitly provide a complete path to the command or it will not be found (unless you have a copy in , of course). The environment variable is explained in Special Shell Variables.

As a workaround, you can determine the path of the executable using the command prior to altering the environment variable.

set GLOBAL_PATH = "$PATH"
set LS = `which ls`
setenv PATH "/usr/local/bin"
$LS
setenv PATH "$GLOBAL_PATH"
unset GLOBAL_PATH

Or, using :

set LS = `which ls`
env PATH='/usr/local/bin' $LS

The use of the backtick (`) operator in this fashion is described in Inline Execution.

Security Note: If your purpose for overriding an environment variable is to prevent disclosure of sensitive information to a potentially untrusted process, you should be aware that if you use for the copy, the called process has access to that temporary copy just as it had access to the original variable. To avoid this, be sure to create the temporary copy using the builtin instead of .

Deleting Shell Variables

For the most part, in Bourne shell scripts, when you need to get rid of a variable, setting it to an empty string is sufficient. However, in long-running scripts that might encounter memory pressure, it can be marginally useful to delete the variable entirely. To do this, use the builtin.

For example:

MYVAR="this is a test"
unset MYVAR
echo "MYVAR IS \"$MYVAR\""

The builtin can also be used to delete environment variables.

C Shell Note: The C shell builtin is identical except that it cannot be used to delete environment variables. Use instead, as shown in Overriding Environment Variables for Child Processes (C Shell).

Also, in C shell, if you try to use a deleted variable, it is considered an error. (In Bourne shell, an unset variable is treated like an empty string.)

NextPrevious


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *