A word from the authorWhen programmers start to use the Solaris product, they want to begin programming scripts immediately. They're not concerned initially with efficiency and elegance; they're concerned with effectiveness. This article explains my proven shell programming techniques to get started quickly. As you become more experienced, you can develop your own programming style and improve the efficiency and elegance of your scripts. Background
The command shell is the layer that interacts with the user and communicates with the operating system. When using MS-DOS, most people use the
Similarly, each UNIX? user must select a command shell to use to communicate to UNIX. When a UNIX account is established, the system administrator selects the user's default shell. Normal options are Bourne Shell ( When you execute a shell script from the command line, your default shell is used. If your default shell is Korn, then the scripts in the article execute without syntax errors. But what if you want others to execute your script? You can't rely on the user's default shell to ensure that your scripts are always run using the Korn shell. The solution is to use a UNIX feature whereby the first line of a shell script indicates under which shell the script is to be executed. The syntax in Code Example 1 forces a script to be run using the Korn shell regardless of what shell the current user is executing. #!/bin/ksh # your script goes here. All lines starting with # # are treated as commentsCode Example 1 - Force a script to be executed by the Korn shell
Some documentation uses a different command prompt symbol to indicate the current shell, as shown in Table 1. (Since this author's favorite shell is the Korn shell, all of the examples in this article use the $-prompt.) Since you cannot ensure that your scripts will always be executed using the Korn shell, put
Table 1 - UNIX prompt symbols Writing a Script - Some BasicsA UNIX script file is similar to a DOS BAT file. All of the programming do's and don'ts from the DOS world still apply in UNIX. Writing any script involves these steps:
Writing a Simple Script
Assume that you want to write a script to capture Run the UNIX Command Interactively
First, look up the documentation for $ vmstat 2 30Code Example 2 - Run the vmstat command interactively 30 times at 2 second intervals
Create a Shell Script
Next, create a script file containing the command. You should establish standards describing script location and script names. Store all things of a specific category, for instance a company, in a subdirectory under
Next, use a text editor such as vi to create a script file called
The script file has two lines in it. The first line leaves nothing to chance, stating that the Korn shell should execute the commands inside this script. The second line is the UNIX command itself. Code Example 3 is a complete listing of #!/bin/ksh vmstat 2 30Code Example 3 - capture_vmstat.sh script to run vmstat 30 times at 2-second intervals
Make the Shell Script Executable
Unlike DOS, which uses the file extension to determine if a file is executable or not, UNIX relies on file permissions. The
The simplest way to turn on the execute-bit is by using Test the Shell Script
Now the script is ready to test. Unlike DOS, UNIX does not automatically look in the current directory for a file to execute. UNIX provides the PATH environment variable. UNIX will only search for executables in directories identified in the PATH variable. Since most people don't include the current directory in the PATH (a dot indicates the current directory), just typing the COMMANDS in Code Example 4 will not work because $ cd /usr/local/acme/scripts $ capture_vmstat.shCode Example 4 - This will NOT execute the script unless "dot" is in the PATH You must explicitly specify the full file name of the script, including path. Do not rely on the PATH variable because it could get changed in the future and one of two things could go wrong. First, the directory where your scripts reside could be inadvertently removed from the PATH and UNIX would no longer be able to locate your scripts. Worse yet, UNIX might find and execute a script by the same name in a different directory, one listed in the new PATH. Therefore, to be safe, you should always execute your scripts by specifying the full file name as shown in Code Example 5. $ /usr/local/acme/scripts/capture_vmstat.shCode Example 5 - Specifying the full file name to ensure UNIX finds the correct script Maybe you don't like typing, so a shortcut relies on the fact that "." (dot) refers to the current directory. First, change to the script directory and then execute the script by prepending "./" (dot-slash) to the script name as shown in Code Example 6. This doesn't save much typing if you are only executing one script; however, if you are going to execute several scripts from your script directory, then you only have to type the directory name once. $ cd /usr/local/acme/scripts $ ./capture_vmstat.shCode Example 6 - Executing the script using the dot-slash notation
Regardless of how you invoke the Launching the ScriptNow you have the script and you know it works. There are four ways to run the script: 1.Interactively Document the script and let others (perhaps the Help Desk staff) run the script file. The folks who run the script don't need to know UNIX commands or syntax in much the same way that DOS users don't need to understand DOS commands or syntax in order to use a BAT file created for them.
2.Using the
Use the
3.Using the
Use the 10 8-17 * * 1,3,5 /usr/local/acme/scripts/capture_vmstat.shCode Example 7 - crontab entry to run the capture_vmstat.sh script
Before moving on to the fourth method for launching your script, you need to understand two problems with running scripts via 4.Using an HTML Form Launch your script using an HTML form and POST your script via CGI (common gateway interface). The output of the command will be sent back to the browser so the <PRE> and </PRE> HTML tags should be used to preserve formatting. There is a bit more to this HTML form method than described here, and there are numerous security risks with using FORM and CGI. However, this method has proven very successful for use by in-house Help Desk staff or other level-one support personnel. Extending the Simple ScriptThe previous script was the shell-script version of "hello, world", the standard first program written when learning a new programming language. Now you can add a few more basic features to it.
Redirecting
First, the script sends its output to #!/bin/ksh vmstat 2 30 > /usr/local/acme/logs/vmstat.logCode Example 8 - Redirecting stdout to a file
But this introduces a couple of new problems. First, every time you run the script it overwrites the contents of the last log file. To correct that, append the new output to the end of the existing log file. Now you need to know when each output in the log was created, since the date-time stamp on the file only indicates when the last one was written. Executing sub-commands within the script
Write the current date and time to the file preceding each execution of the script. Use #!/bin/ksh echo "#--- $(date)" >> /usr/local/acme/logs/vmstat.log vmstat 2 30 >> /usr/local/acme/logs/vmstat.logCode Example 9 - Appending stdout to a log file
In Code Example 10, the Korn shell is instructed to run the
# store current date as YYYYMMDD in variable DATE for later
# use
export DATE=$(date +m%d)
# count number of established socket connections and write.
# to log
export CTR_ESTAB=$(netstat -na -P tcp | grep ESTABLISH | wc
-l)
export CTR_CLOSE_WAIT=$(netstat -na -P tcp | grep CLOSE WAIT
| wc -l)
echo "${DATE} ${CTR_ESTAB} ${CTR_CLOSE_WAIT} >> ${LOG_FILE}
Code Example 10 - Using $(xxx) to execute a command within a Korn shell script
Generating Unique File NamesWhat happens if multiple users run the script concurrently? The output from each script would be interleaved in the output file since each instance of the script would be writing to the same output file. You can create a unique output file name by placing the PID number (represented by $$) in the file name, as shown in Code Example 11. #!/bin/ksh echo "#--- $(date)" >> /usr/local/acme/logs/vmstat.$$.log vmstat 2 30 >> /usr/local/acme/logs/vmstat.$$.logCode Example 11 - Using $$ to generate unique file names using current PID
When the next user runs the script, a different PID will be assigned to the script's execution, thus causing a separate log file to be created each time instead of appending to the existing log file. Maybe that's not a bad thing, but it's not what you want to achieve.
Another possibility, instead of using an environment variable whose value is changed each time the script is executed, is to use an environment variable that is set once, outside the script, prior to the execution of the script. UNIX automatically sets the
#!/bin/ksh
echo "#--- $(date)"
>> /usr/local/acme/logs/vmstat.${LOGNAME}.log
vmstat 2 30
>> /usr/local/acme/logs/vmstat.${LOGNAME}.log
Code Example 12 - Generating a file name using an environment variable whose value is externally set
Structured Programming Techniques
Two final touch-ups and you're finished with your basic Korn shell script. First, what if you want to change the frequency or duration of the Second, what if you change your mind about the log file naming convention? This is not something you want the user to have to provide each time using a command line argument. However, if you have hard-coded the log file name in multiple lines within the script, then when you decide to use a different naming convention, you will have to search every line of the script to see where the name was specified. Instead, store the log file name in an environment variable and modify each command to append output to the file name contained in the variable. Then, when you change the log file naming convention, all you need to do is modify the one line where the environment variable is set.
#!/bin/ksh
# ----------------------------------------------------
# capture_vmstat.sh <INTERVAL> <COUNT>
# <INTERVAL> vmstat interval
# <COUNT> vmstat count
# run vmstat and capture output to a log file
#-----------------------------------------------------
# indicate defaults for how often and for how long
# to run vmstat
export INTERVAL=2 # every 2 seconds
export COUNT=30 # do it 30 times
# obtain command line arguments, if present
if [ "${1}" != "" ]
then
INTERVAL=${1}
# if there is one command line argument,
# maybe there's two
if [ "${2}" != "" ]
then
COUNT=${2}
fi
fi
# directories where scripts and logs are stored
export PROGDIR=/usr/local/acme/scripts
export LOGDIR=/usr/local/acme/logs
# define logfile name and location
export LOG_FILE=${LOGDIR}/capture_vmstat.${LOGNAME}.log
# write current date/time to log file
echo "#--- $(date)" >> ${LOG_FILE}
vmstat ${INTERVAL} ${COUNT} >> ${LOG_FILE}
# say goodnight, Gracie
exit 0
Code Example 13 - A more robust version of the capture_vmstat.sh script
Writing a
| ||||||||||||||||
|
| ||||||||||||