cs534 Operating Systems - The Bourne Again Shell (BASH)
Background
- The Bourne Again Shell (bash) is based on the Bourne Shell (sh)
- The Bourne Shell was developed for AT&T Bell Labs UNIX by computer scientist Steve Bourne
- The Bourne Shell is still the most commonly used UNIX shell
- The bash contains many features not found in sh, but is backward compatible with sh
- Most sh scripts will run under bash
Shell Basics
There are three kinds of shells:
- interactive login shells
- runs /etc/profile, ~/.bash_profile,~/.bash_logout
- interactive non-login shells
- runs /etc/.bashrc or ~/.bashrc
- non-nnteractive login shells
- the BASH_ENV variable calls a specified startup file
- Note about PATHs
- the PATH statement is best placed in .bashrc
- why? because .bashrc is run when a interactive non-login shell is run
- since subshells INHERIT EXPORTED variables, the PATH can be
used by interactive non-login shells
Running a startup file in the Current Shell
- If you make changes to a startup file (script),
the changes will not take effect until the script is run again.
- You don't have to wait until the next time you login to run the
script and use the new features...
- using . .bashrc (for instance) or
source ~/.bashrc will rerun the script without logging out
- Using . or source, you can launch ANY script
File Descriptors and Redirection
When a new process is spawned, three file descriptors are also created:
| Name | Symbol | Default Device |
| Standard In | 0< | Keyboard |
| Standard Out | 1> | Monitor |
| Standard Error | 2> | Monitor |
Send Standard Out and Standard Error to different files
Assume that File2 does NOT exist
$ cat File2 File1 > holder.txt 2> error.txt
What Happened?
cat produced an error message that was redirected to
the file error.txt. The contents of File1 were redirected to
the file holder.txt.
$ cat holder.txt
This is File1
$ cat error.txt
cat: File2: No such file or directory
Send Standard Out and Standard Error to the same file
NOTE: The construct 2>&1 means redirect Standard Error to the
same place as Standard out...or,
Standard Error becomes a duplicate of Standard Out
$ cat File2 File1 > holder.txt 2>&1
$ cat holder.txt
cat: File2: No such file or directory
This is File1
NOTE: Order of the arguments is important.
$ cat File2 File1 2>&1 > holder.txt
Problem:
Standard Error is redirected to Standard Out
BEFORE Standard Out is redirected to holder.txt
That means that Standard Out is still defaulting to
the monitor at the time Standard Error is redirected
to Standard Out, Standard Error goes to the monitor.
Standard Out goes to the file holder.txt
Now we can send both Standard Out and Standard Error through a pipe
$ cat File2 File1 2>&1 | tr "[a-z]" "[A-Z]"
CAT: FILE2: NO SUCH FILE OR DIRECTORY
THIS IS FILE 1
What Happened?
Since Standard Error is made a duplicate of Standard Out,
everything goes through the pipe and gets translated.
Shell Scripts
- A shell script is a file containing commands that are executable by the shell
- A shell script is like a batch file on steroids
- Shell scripts accept ambiguous file references, pipes, redirection, compiled user programs, built-in utilities, and other shell scripts
- Shell scripts can contain control structures (program flow control) like those found in programming languages
- Flow control structures allow the manipulation and alteration of the flow of the execution of the elements contained in a script (or program) based on the requirements of the job
- Any legal command or group of commands can be run from a shell script
- By convention, the FIRST LINE of the script contains the "sh-bang" statement
- The sh-bang statement tells the system the path of which shell to run the script under
Example sh-bang statement
#!/bin/bash
- In this case, the script will be run under the bourne-again-shell (bash)
Here is a small script
#!/bin/bash
echo "The current time and date is " `date` "
echo "These are the users that are currently on the system: "
who
Here's the output
rgrogan@analog24: $ source whoson.bash
The current time and date is Wed Oct 17 19:33:49 PDT 2007
These are the users currently logged on to the system
cs53412 pts/0 2007-10-17 17:54 (207.233.45.19)
cs53419 pts/1 2007-10-17 19:16 (207.233.45.19)
cs53415 pts/2 2007-10-17 17:45 (207.233.45.19)
cs53432 pts/3 2007-10-17 19:18 (207.233.45.19)
cs53409 pts/5 2007-10-17 19:29 (207.233.45.19)
cs53405 pts/6 2007-10-17 19:14 (207.233.45.19)
rgrogan pts/7 2007-10-17 19:29 (207.233.45.19)
rgrogan@analog24: $
Invoking a Shell Script
- With the exception of shell built-ins, when the shell is given a command line to execute, the shell forks, creating a sub-shell
- The sub-shell attempts to execute the command using the system call exec()
- If the command is an executable program, exec() generally succeeds
- If the command is a shell script, exec() will fail
- When exec fails, the systems assumes that the command is a shell script
- The sub-shell then runs the commands in the script
- The sub-shell takes input from a file: the file is the shell script
- The sub-shell does not take input from the command line as does the login shell
- There are at least two ways to run a shell script
- Remember that when a document is created with a text editor (like vi), the execute permission is not typically set
- Since this is the case, a shell script cannot be run from the shell because the execute permission of the file is not set...even if you are the owner of the script
- The execute permissions can be changed by using chmod
Example:
$ chmod u+x filename will give the owner execute permissions
- With the execute permission set, the user (owner in this case) can execute the shell script directly from the command line
- Obviously, permissions must be set for group and other for execution by all users
Example:
$ shell_script_name
Shell scripts can be run even if the user does not have execute permission
- This is done by using a bash command to exec a new shell that will run the script directly
Example
$ bash shell_script_name
Note
- The second method is inferior to the first
- Why? Because the script runs slower due to the extra layer of complexity created by the new shell and the system overhead involved
Separating and Grouping Commands
ShellCommandGrouping.pdf
Parameters and Variables
- Inside the shell, a shell parameter is associated with a value that is typically accessible to the user
- Shell parameters are sometimes called shell variables (variables for short)
- There are several kinds of shell variables
- Variable names consist of letters, digits and underscores
- Variable names cannot start with a digit
- Examples of Legal Variable Names
- myVar
- chk_vars
- del_3_files
- MY_PATH
- Examples of Illegal Variable Names
- 23Pages
- MY PATH
- 3-blind-mice
- EXPORT variables are accessible to shells and other programs
- EXPORT variable names are usually uppercase, most other variable names are MixedCase
- A variable is a place in memory that contains a value
- A variable name is an alias for the address of the memory cell(s)
- Variable syntax is:
VARIABLE=value
- System Variables (HOME, PATH, etc) are reserved for system use. Note the use of uppercase
- User-Defined variables are created by users and cannot use RESERVED WORDS
Some Considerations
- The $ (dollar-sign) is the "contents of" operator
- To see or use the contents of a variable, the variable MUST be
preceded by a DOLLAR-SIGN
Example:
$ myName=Mitch
$ echo myName
myName
$ echo $myName
Mitch
- When using STRINGS with WHITESPACE characters, double quotes
must be used to render the string AS WRITTEN
Example:
$ myString="Happy Halloween"
$ echo $myString
Happy Halloween
$ echo "$myString"
Happy Halloween
$ echo "Today is special...$myString"
Today is special...Happy Halloween
$
- Note that the variable was EXPANDED (contents shown) with double quotes
- What about SINGLE QUOTES?
Example:
$ myString="Happy Halloween"
$ echo '$myString'
$myString
$ echo 'Today is special...$myString'
Today is special...$myString
- What if you escape the dollar-sign? Will the contents of the variable be usable?
Example:
$ myName=Mitch
$ echo $myName
Mitch
$ echo \$myName
$myName
$
- Be careful with strings and whitespace characters
Example:
$ people="George and Gracie"
$ echo $people
George and Gracie
$ echo \$myName
$myNamy
$ people=George and Gracie
bash: and: command not found
The export Builtin
- Variables are usually local to the process in which they are declared
- The export builtin is used to make variables available to child processes (other processes)
- When export is used, a copy of the variable used as an argument to export is placed in the environment of the child process for its own use
Example without the use of export
here are the scripts
bash$ cat extest1 // a little test script
cheese=american
echo "extest1 1: $cheese" // echo contents of cheese 1st time
subtest // execute script named subtest
echo "extest1 2: $cheese" // echo contents of cheese 2nd time
bash$ cat subtest // contents of script subtest
echo "subtest 1: $cheese" // subtest can’t see contents of cheese from //above
cheese=swiss // assign a value to cheese in subtest
echo "subtest 2: $cheese" // echo contents of cheese 2nd time
here's the run...no export
bash$ extest1 // run the script
extest1 1: american
subtest 1: // american is LOCAL to extest1
subtest 2: swiss // swiss is LOCAL to subtest
extest1 2: american // swiss is not global…american is LOCAL
Example using export
here are the scripts
bash$ cat extest2
export cheese // value of cheese is now GLOBAL
cheese=american
echo "extest2 1: $cheese"
subtest // run script called subtest
echo "extest2 2: $cheese"
bash$ cat subtest
echo "subtest 1: $cheese" // use GLOBAL value of cheese
cheese=swiss // assign a LOCAL value to cheese
echo "subtest 2: $cheese" // display LOCAL value of cheese
here's the run...using export
bash$ extest2
extest2 1: american // global
subtest 1: american // global
subtest 2: swiss // local
extest2 2: american // global
Example using export in combination with a variable declaration
here are the scripts
bash$ cat extest3
export cheese=american // global status and assignment on same line
echo "extest3 1: $cheese"
subtest
echo "extest3 2: $cheese"
bash$ cat subtest
echo "subtest 1: $cheese"
cheese=swiss
echo "subtest 2: $cheese"
here's the run...using export in combination with a variable declaration
bash$ extest3
extest3 1: american
subtest 1: american
subtest 2: swiss
extest3 2: american
Pathname Expansion
Removing a variable with unset
declare and typeset assign attributes to variables
- declare and typeset mean and do the same thing
- they set attributes and values for shell variables
- See table 8-3 page 282 for commonly used shell variable attributes
Example:
the PATH environment keyword
- A path statement provides the shell places to look in the filesystem
when trying to find a command with the corresponding name
- Note that by default, your home directory IS NOT in the path
- By default, when a NEW shell is spawned, the PATH statement doesn't
exist for the new shell
- Use the export command to provide access to the path for all sub-shells
Example:
export PATH=/usr/local/bin:/usr/bin:/bin
- IMPORTANT: a single colon as the FIRST character in the path,
a single colon as the LAST character in the path, or any two colons
with nothing between them (anywhere in the path statement) represenr the
CURRENT WORKING DIRECTORY
Example 1:
export PATH=/usr/local/bin:/usr/bin:/bin:
- In the case above, the current directory is at the END of the path.
Example 2:
export PATH=/usr/local/bin::/usr/bin:/bin
- In the case above, the current directory is in the MIDDLE of the path.
Example 3:
export PATH=:/usr/local/bin::/usr/bin:/bin
- In the case above, the current directory is the FIRST directory of the path.
- With regard to the working directory being FIRST in the path, note the security precaution given
on page 285 of the text
The Command Line Prompts
- PS1 is the primary user prompt. In BASH the default prompt can be changed
See table 8-4, page 287 for PS1 symbols
- PS2 is the secondary user prompt. In BASH, it usually is used to indicate
that the system is waiting for more input. BASH default is >
- PS3 is the menu prompt. for use with the select control structure
- PS4 is the debugging prompt. BASH can run a script one line at a time to help
find a problem that occurs
- The default symbol is the plus ( + ) sign, and it precedes each line that is run
- Note: PS4 must be exported from the shell that creates the sub-shell,
to the shell that will actually run the script
Process Structure
- Processes are hierarchical
- Processes have a root, parents, and children
- Parent processes fork (spawn) child processes
- fork() is the name of the system call that creates a new process
- When a UNIX machine is booted, PID number 1 is initiated and the process is called init
- init is the mother of all processes during the life of the session (until the system is brought down)
- If terminals are attached to the system, init forks a getty process for each terminal
- When a user logs in to the terminal the getty process becomes a login process
- The login process then becomes the user’s shell process
Processes
Various Summaries
- Table 8-5, page 290 summarizes bash keyword variables
- Table 8-6, page 291 summarizes special shell characters
Single/Double Quoting in Aliases
- Using the appropriate quoting method is critical when using variables in aliases
Example using double-quotes:
rgrogan@analog24: $ echo $PWD
/home/rgrogan
rgrogan@analog24: $ alias dir1=" echo working directory is $PWD"
rgrogan@analog24: $ alias dir1
alias dir1=' echo working directory is /home/rgrogan'
rgrogan@analog24: $
Example using single-quotes:
rgrogan@analog24: $ echo $PWD
/home/rgrogan
rgrogan@analog24: $ alias dir2=' echo working directory is $PWD'
rgrogan@analog24: $ alias dir2
alias dir2=' echo working directory is $PWD'
rgrogan@analog24: $
The Order of Command Line Expansion
- Brace expansion
Example:
$ echo List_{AA, BB, CC}
List_AA List_BB List_CC
- Tilde Expansion...remember the ~ stands for your home directory...see page 326
- Parameter and Variable Expansion - $myVar will be expanded
...quoting type comes into play here
- Arithmetic Expansion - $((expression))...will be discussed later
- Command Substition - $(command)...echo "The date is $(date)"
- Word Splitting: will discuss this later
- Pathname Expansion -
Example:
$ ls
tmp1 tmp2 tmp3
$ echo tmp*
tmp1 tmp2 tmp3
$ rm tmp*
$ echo tmp*
tmp*
$