Table of Contents
Here are some notes on C-Shell scripts. It's not all encompassing, but it covers most of what I do with a shell script. If I need to do more then I usually switch to Perl.
Pound Shebang
The # is a pound sign, and the ! is the shebang. The #! (Pound Shebang) indicates the interpreter program that should run the script. This can be any of the many shell programs, Perl, PHP, Python or even your own custom program. I'm pretty sure all Unix shells support Pound Shebang, it's not C-Shell specific. A C-Shell script should always start with the following line.
#!/bin/csh
C-Shell Command Line Arguments
Usually a C-Shell script has one more more commandline arguments. $#argv indicates the number of arguments. This example prints a message and exits if there are less than two arguments entered.
if ($#argv<2) then
echo "Error - Not enough arguments. Script aborting."
exit
endif
Set Variables
The command line arguments are stored in array $argv. The first argument is in $argv[1], the second in $argv[2] and so on.
The set command assigns a value to a variable. In this example the first argument contains the sitename. Variables are set to a value without the $-sign and are accessed with the $-sign.
set sitename = $argv[1]
echo $sitename
In the following example default values are assigned to indicate what tasks the script will do. In this example the default is to do nothing so all to do variables default to 0 (false). The default values may be over-ridden by command-line arguments in a subsequent example.
set do_backup = 0
set do_wget = 0
set do_gsutil = 0
C-Shell Flow Control
Foreach loop
You can loop through each argument using the foreach command. Note the variable arg does NOT have a $-sign in the foreach line, but it does have a $-sign when it is used.
foreach arg ($argv)
echo "argument = " $arg
end
If Statement
When an if statement has only one command to execute then you can put the if statement and the command on a single line.
IMPORTANT NOTE:
In the following example the == has a ' ' space on each side. This is needed and the script will not function correctly without these spaces. This is an annoying quirk of the C-Shell, but it's not too significant if you know about it... which you now do.
foreach arg ($argv)
if ($arg == '1') set do_wget = 1
if ($arg == '2') set do_backup = 1
if ($arg == '3') set do_delete = 1
end
if ($do_wget) echo "do_wget"
if ($do_backup) echo "do_backup"
if ($do_delete) echo "do_delete"
If multiple commands are to be executed within the if statement then you need then on the if line and you need endif at the end.
if ($do_wget) then
wget -r php.${sitename}
echo "Creating deleteme.script"
diff -rqs php.${sitename} php.${sitename}.orig |grep ' are identical$' |sed 's#^Files \(.*\) and .*#rm -rfv #' > deleteme.script
endif
C-Shell supports the else. Note, you do NOT need the endif before the else. In the following example, nested if statements use the -e file existence check to determine what files should be copied.
if ($do_backup) then
if (-e php.${sitename}) then
if (-e php.${sitename}.orig) then
echo "Moving 'php.${sitename}' to 'php.${sitename}.backup'"
echo "You will want to move 'php.${sitename}.backup' to 'php.${sitename}.orig' so the diff/delete_unchanged phase works"
cp -rf php.${sitename} php.${sitename}.backup
else
echo "Moving 'php.${sitename}' to 'php.${sitename}.orig'"
cp -rf php.${sitename} php.${sitename}.orig
endif
endif
endif
The following example runs a script if it exists. The -e file existence check is used. The ! -e indicates that the file does not exist.
if ($do_delete) then
if ( -e deleteme.script ) source deleteme.script
if ( ! -e deleteme.script ) echo "deleteme.script does not exist"
end if
Here is a list of CShell file checks that I am aware of.
-d file file is a directory
-e file file exists
-f file file is an ordinary file
-r file file is readable by user
-o file file is owned by user
-w file file is writable by user
-x file file is executable by user
-z file file has size 0
In the following example the foreach loop iterates through a list of numbers.
foreach i (1 2 3 4)
echo $i
end
The following example is another way to iterate through a range of numbers. There are two things worth notingis this example.
- The Unix/Linux seq first step last command generates a sequence. This command is available on the command-line of most Unix/Linux shells.
- The backtick puts the stdout output of the embedded command(s) onto the command line. This is also available in most Unix/Linux shells.
In the following example, the empty sub-directories in php.1, php.2, php.3 and php.4 are found and deleted.
foreach i (`seq 1 1 4`)
rm -rf `find php.${sitename} -empty`
end
The following example loops through a list of files returned by glob *.txt. A backup is made of each file.
foreach file (*.txt)
cp $file $file.bck
end
Changing Directories in Script
The pushd command can be used to change into a directory and the the popd command returns to the original directory after the work is completed.
pushd php.${sitename}
pwd
popd
pwd
Show Progress
The echo command prints text stdout.
echo 'Done!'