leader

C Shell Scripting

View Markdown

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.

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!'