Appearance
csh - C Shell
The C Shell (csh) is a Unix shell developed by Bill Joy at the University of California, Berkeley, first released in 1978. Designed to provide a more C-like syntax for interactive use, csh introduced many features that became standard in later shells, including command history, aliases, and job control. While csh and its enhanced version tcsh are primarily used for interactive sessions rather than scripting, they remain important in certain Unix environments and offer unique features that some users prefer. Understanding csh is valuable for system administrators and users who encounter it in legacy systems or specific Unix distributions.
Installation and Setup
C Shell Variants
csh
# Check which csh variant is available
which csh
/bin/csh
which tcsh
/usr/bin/tcsh
# Check shell version
echo $version
# tcsh 6.22.04 (Astron) 2021-04-26 (x86_64-unknown-linux) options wide,nls,dl,al,kan,rh,color,filec
# Check if running csh or tcsh
echo $shell
/bin/tcsh
Installing C Shell
csh
# Ubuntu/Debian
sudo apt update && sudo apt install csh tcsh
# CentOS/RHEL/Fedora
sudo dnf install tcsh
# macOS (tcsh is usually pre-installed)
# For csh specifically:
brew install tcsh
# Arch Linux
sudo pacman -S tcsh
# FreeBSD (usually pre-installed)
pkg install tcsh
# Check installation
csh --version
tcsh --version
Setting csh/tcsh as Default Shell
csh
# Check current shell
echo $SHELL
# Add csh to available shells
echo /bin/csh | sudo tee -a /etc/shells
echo /bin/tcsh | sudo tee -a /etc/shells
# Set tcsh as default shell (recommended over csh)
chsh -s /bin/tcsh
# Verify change (restart terminal)
echo $SHELL
/bin/tcsh
Basic Configuration Files
csh
# Configuration files for csh/tcsh
~/.cshrc # Main configuration file
~/.tcshrc # tcsh-specific configuration
~/.login # Login shell configuration
~/.logout # Logout script
# Create basic .tcshrc
cat > ~/.tcshrc << 'EOF'
# tcsh configuration
# Set environment variables
setenv EDITOR vi
setenv PAGER less
setenv LANG en_US.UTF-8
# Set path
set path = (/usr/local/bin /usr/bin /bin $path)
# Aliases
alias ll 'ls -l'
alias la 'ls -la'
alias h 'history'
alias .. 'cd ..'
# Prompt
set prompt = '%n@%m:%c$ '
# History
set history = 1000
set savehist = 1000
# Completion
set autolist
set complete = enhance
# Other options
set noclobber
set notify
EOF
# Source configuration
source ~/.tcshrc
C Shell Syntax and Variables
Variable Assignment and Usage
csh
# Simple variable assignment
set name = "John Doe"
set age = 30
set path_var = "/home/user"
# Using variables
echo $name
echo "Hello, $name"
echo 'Literal: $name' # Single quotes prevent expansion
# Array variables
set fruits = (apple banana orange)
set numbers = (1 2 3 4 5)
# Accessing array elements
echo $fruits[1] # First element (1-indexed)
echo $fruits[2] # Second element
echo $fruits[$#fruits] # Last element
echo $fruits[*] # All elements
echo $#fruits # Number of elements
# Environment variables
setenv PATH "/usr/local/bin:$PATH"
setenv EDITOR vi
setenv HOME /home/user
# Unset variables
unset name
unsetenv PATH # Dangerous!
# Special variables
echo $0 # Shell name
echo $$ # Process ID
echo $? # Exit status of last command
echo $#argv # Number of arguments
echo $argv[*] # All arguments
String Operations
csh
# String concatenation
set first = "Hello"
set second = "World"
set combined = "$first, $second!"
echo $combined # Hello, World!
# String length (tcsh)
set string = "Hello, World!"
echo $%string # Length: 13
# Substring operations (limited in csh)
set filename = "document.txt"
set basename = $filename:r # Remove extension: document
set extension = $filename:e # Get extension: txt
set dirname = $filename:h # Get directory (if path)
set tail = $filename:t # Get filename (if path)
# Case conversion (tcsh)
set upper = $string:u # Uppercase
set lower = $string:l # Lowercase
Command Substitution
csh
# Command substitution using backticks
set current_date = `date`
set file_count = `ls | wc -l`
set user_home = `eval echo ~$USER`
# Using command substitution in expressions
echo "Today is `date +%A`"
set files = (`ls *.txt`)
# Nested command substitution
set day_of_week = `date +%A`
echo "Today is $day_of_week, `date +%B` `date +%d`"
Control Structures
Conditional Statements
csh
# if-then-else
if ($age > 18) then
echo "Adult"
else if ($age == 18) then
echo "Just turned adult"
else
echo "Minor"
endif
# String comparisons
if ("$name" == "John") then
echo "Hello John"
endif
if ("$name" != "John") then
echo "Not John"
endif
# File tests
if (-f "file.txt") then
echo "File exists"
endif
if (-d "directory") then
echo "Directory exists"
endif
if (-r "file.txt") then
echo "File is readable"
endif
if (-w "file.txt") then
echo "File is writable"
endif
if (-x "script.sh") then
echo "File is executable"
endif
# Logical operators
if ($age > 18 && $age < 65) then
echo "Working age"
endif
if ($status == 0 || $force == "true") then
echo "Proceeding"
endif
if (! -f "file.txt") then
echo "File does not exist"
endif
Switch Statements
csh
# switch statement
switch ($variable)
case pattern1:
echo "Matched pattern1"
breaksw
case pattern2:
case pattern3:
echo "Matched pattern2 or pattern3"
breaksw
default:
echo "No pattern matched"
breaksw
endsw
# Switch with file extensions
switch ($filename)
case *.txt:
echo "Text file"
breaksw
case *.jpg:
case *.png:
case *.gif:
echo "Image file"
breaksw
case *.sh:
echo "Shell script"
breaksw
default:
echo "Unknown file type"
breaksw
endsw
Loops
csh
# foreach loop
foreach item (apple banana orange)
echo "Fruit: $item"
end
# foreach with array variable
set files = (*.txt)
foreach file ($files)
echo "Processing: $file"
end
# foreach with command substitution
foreach user (`cat users.txt`)
echo "User: $user"
end
# while loop
set counter = 1
while ($counter <= 10)
echo "Counter: $counter"
@ counter++
end
# while loop with file reading
set line = ""
while (1)
set line = $<
if ($line == "") break
echo "Line: $line"
end
# Nested loops
foreach dir (/usr /opt /var)
foreach file ($dir/*)
if (-f $file) then
echo "File: $file"
endif
end
end
Arithmetic Operations
Arithmetic with @ Command
csh
# Basic arithmetic
@ result = 5 + 3 # 8
@ result = 10 - 4 # 6
@ result = 6 * 7 # 42
@ result = 20 / 4 # 5
@ result = 17 % 5 # 2 (modulo)
# Arithmetic with variables
set num1 = 10
set num2 = 5
@ sum = $num1 + $num2 # 15
@ product = $num1 * $num2 # 50
# Increment and decrement
set counter = 0
@ counter++ # Increment
@ counter-- # Decrement
@ counter += 5 # Add and assign
@ counter -= 3 # Subtract and assign
# Complex expressions
@ result = ($num1 + $num2) * 2
@ result = $num1 ** 2 # Exponentiation (tcsh)
# Comparison operations
@ is_greater = ($num1 > $num2) # Returns 1 if true, 0 if false
if ($is_greater) then
echo "num1 is greater than num2"
endif
External Arithmetic Tools
csh
# Using expr for complex calculations
set result = `expr 5 + 3`
set result = `expr $num1 \* $num2` # Note: * must be escaped
# Using bc for floating point
set result = `echo "scale=2; 10/3" | bc`
set result = `echo "scale=4; sqrt(16)" | bc -l`
# Using awk for calculations
set result = `awk "BEGIN {print 10/3}"`
Aliases and History
Alias Management
csh
# Simple aliases
alias ll 'ls -l'
alias la 'ls -la'
alias h 'history'
alias .. 'cd ..'
alias ... 'cd ../..'
# Aliases with arguments
alias rm 'rm -i' # Interactive removal
alias cp 'cp -i' # Interactive copy
alias mv 'mv -i' # Interactive move
# Complex aliases
alias lsd 'ls -l | grep "^d"' # List only directories
alias psg 'ps aux | grep' # Process search
# Conditional aliases
if (-f /usr/bin/vim) then
alias vi vim
endif
# List aliases
alias # Show all aliases
alias ll # Show specific alias
# Remove aliases
unalias ll
unalias * # Remove all aliases
History Management
csh
# History configuration
set history = 1000 # Number of commands to remember
set savehist = 1000 # Number of commands to save to file
# History commands
history # Show all history
history 10 # Show last 10 commands
history -r # Read history from file
history -w # Write history to file
# History expansion
!! # Previous command
!n # Command number n
!string # Last command starting with string
!?string # Last command containing string
^old^new # Replace old with new in previous command
# History modifiers
!:0 # Command name only
!:1 # First argument
!:$ # Last argument
!:* # All arguments
!:1-3 # Arguments 1 through 3
# Examples
echo !$ # Echo last argument of previous command
cp file.txt !$.bak # Copy file with .bak extension
Job Control and Process Management
Job Control
csh
# Background jobs
command & # Run command in background
jobs # List active jobs
fg %1 # Bring job 1 to foreground
bg %1 # Send job 1 to background
kill %1 # Kill job 1
# Job control signals
# Ctrl+C: Interrupt (SIGINT)
# Ctrl+Z: Suspend (SIGTSTP)
# Ctrl+\: Quit (SIGQUIT)
# Process management
ps # Show current processes
ps aux # Show all processes
kill PID # Terminate process
kill -9 PID # Force kill process
killall process_name # Kill all processes by name
# Nohup equivalent
nohup command & # Run command immune to hangups
Process Information
csh
# Process variables
echo $$ # Current shell PID
echo $! # PID of last background job
# Process status
echo $? # Exit status of last command
echo $status # Same as $? in csh
# Wait for processes
wait # Wait for all background jobs
wait %1 # Wait for specific job
Input/Output and Redirection
Basic I/O Redirection
csh
# Output redirection
command > file.txt # Redirect stdout to file
command >> file.txt # Append stdout to file
command >& file.txt # Redirect both stdout and stderr
command >>& file.txt # Append both stdout and stderr
# Input redirection
command < input.txt # Read input from file
sort < unsorted.txt > sorted.txt
# Pipes
ls -l | grep "txt" # Pipe output to grep
ps aux | grep "process" | wc -l # Count matching processes
# Here documents (limited support)
cat << EOF
This is a here document
Variables like $HOME are expanded
EOF
Advanced I/O Features
csh
# Noclobber option
set noclobber # Prevent overwriting files
command >! file.txt # Force overwrite with noclobber set
# Tee equivalent
command | tee file.txt # Write to file and stdout
# Error redirection
command >& /dev/null # Redirect both stdout and stderr to null
(command > output.txt) >& error.log # Separate stdout and stderr
Built-in Commands and Features
Essential Built-ins
csh
# echo command
echo "Simple message"
echo -n "No newline" # tcsh only
# printf (tcsh only)
printf "%s: %d\n" "Count" 42
printf "%-10s %5d\n" "Name" 123
# set and setenv
set var = value # Local variable
setenv VAR value # Environment variable
# which and where
which command # Show command location
where command # Show all command locations (tcsh)
# Directory operations
cd directory # Change directory
pushd directory # Push directory onto stack
popd # Pop directory from stack
dirs # Show directory stack
# File operations
ls -l # List files
cp source dest # Copy files
mv old new # Move/rename files
rm file # Remove files
mkdir directory # Create directory
rmdir directory # Remove empty directory
tcsh-Specific Features
csh
# Command completion
set complete = enhance # Enhanced completion
set autolist # Automatically list completions
# Spelling correction
set correct = cmd # Correct commands
set correct = complete # Correct completions
set correct = all # Correct everything
# File completion
set filec # Enable filename completion
# Auto-logout
set autologout = 60 # Auto-logout after 60 minutes
# Watch for logins
set watch = (any any) # Watch for any user login
set who = "%n has %a %l from %M at %t." # Login message format
Configuration and Customization
Prompt Customization
csh
# Simple prompts
set prompt = '%n@%m:%c$ ' # user@host:dir$
set prompt = '% ' # Simple %
set prompt = '\! % ' # History number %
# Prompt escape sequences
# %n - Username
# %m - Hostname
# %c - Current directory (basename)
# %C - Current directory (full path)
# %/ - Current directory (full path)
# %~ - Current directory (with ~ substitution)
# %t - Time (12-hour)
# %T - Time (24-hour)
# %p - Time (AM/PM)
# %d - Day of week
# %D - Date
# %w - Month
# %W - Year
# %! - History number
# %# - # if root, % otherwise
# Advanced prompt with colors (tcsh)
set prompt = '%{\033[1;32m%}%n@%m%{\033[0m%}:%{\033[1;34m%}%c%{\033[0m%}$ '
# Multi-line prompt
set prompt = '%n@%m:%c\
$ '
# Conditional prompt
if ($uid == 0) then
set prompt = 'root@%m:%c# '
else
set prompt = '%n@%m:%c$ '
endif
Environment Configuration
csh
# Path management
set path = (/usr/local/bin /usr/bin /bin)
set path = ($path /opt/bin) # Append to path
# Environment variables
setenv EDITOR vi
setenv PAGER less
setenv BROWSER firefox
setenv LANG en_US.UTF-8
# Platform-specific configuration
switch (`uname`)
case Linux:
setenv LS_COLORS 'di=34:ln=35:so=32:pi=33:ex=31:bd=46;34:cd=43;34:su=41;30:sg=46;30'
breaksw
case Darwin:
setenv LSCOLORS ExFxCxDxBxegedabagacad
breaksw
endsw
# Conditional environment
if (-d "$HOME/.local/bin") then
set path = ($HOME/.local/bin $path)
endif
if ($?DISPLAY) then
setenv BROWSER firefox
else
setenv BROWSER lynx
endif
Shell Options
csh
# Important shell options
set noclobber # Prevent file overwriting
set notify # Report job status immediately
set noglob # Disable filename expansion
set ignoreeof # Don't exit on Ctrl+D
# tcsh-specific options
set autolist # List completions automatically
set complete = enhance # Enhanced completion
set correct = cmd # Correct commands
set filec # Filename completion
set histdup = erase # Remove duplicate history entries
set listjobs = long # Long format for job listing
set rmstar # Ask before rm *
Scripting Considerations
Script Structure
csh
#!/bin/csh -f
# Script description
# Note: -f flag prevents reading .cshrc
# Variable declarations
set script_name = $0:t
set script_dir = $0:h
set version = "1.0"
# Function equivalent (using goto/label)
goto main
usage:
echo "Usage: $script_name [options] [arguments]"
echo "Options:"
echo " -h Show this help"
echo " -v Show version"
exit 0
version:
echo "$script_name version $version"
exit 0
error:
echo "Error: $error_msg"
exit 1
main:
# Parse arguments
while ($#argv > 0)
switch ($argv[1])
case -h:
goto usage
case -v:
goto version
case -*:
set error_msg = "Unknown option: $argv[1]"
goto error
default:
break
endsw
shift argv
end
# Main script logic
echo "Script execution completed"
exit 0
Best Practices for csh Scripts
csh
# Use tcsh instead of csh for scripts
#!/bin/tcsh -f
# Always use -f flag to avoid .cshrc interference
#!/bin/csh -f
# Error handling
set error_exit = 0
if (! -f "required_file.txt") then
echo "Error: Required file not found"
set error_exit = 1
endif
if ($error_exit) exit 1
# Input validation
if ($#argv == 0) then
echo "Error: No arguments provided"
exit 1
endif
# Safe variable usage
if ($?variable) then
echo "Variable is set: $variable"
else
echo "Variable is not set"
endif
# Avoid complex scripting in csh
# Use sh/bash for complex scripts
# Use csh/tcsh primarily for interactive use
Limitations and Alternatives
Known Limitations
csh
# csh scripting limitations:
# 1. No functions (use goto/labels instead)
# 2. Limited error handling
# 3. No local variables in "functions"
# 4. Inconsistent syntax
# 5. Poor signal handling
# Example of workaround for function-like behavior
goto main
# "Function" using goto/label
process_file:
set file = $1
if (-f $file) then
echo "Processing $file"
# Process file here
else
echo "File $file not found"
endif
goto return_point
main:
set return_point = main_continue
set argv[1] = "test.txt"
goto process_file
main_continue:
echo "Back in main"
exit 0
When to Use csh/tcsh
csh
# Good for:
# - Interactive shell use
# - Simple automation tasks
# - Users familiar with C-like syntax
# - Legacy system compatibility
# Not recommended for:
# - Complex scripting (use bash/sh instead)
# - Portable scripts
# - Production automation
# - Error-critical applications
# Migration example from csh to bash
# csh version:
# if ($status == 0) then
# echo "Success"
# endif
# bash equivalent:
# if [ $? -eq 0 ]; then
# echo "Success"
# fi
Interoperability
csh
# Running bash scripts from csh
bash script.sh
# Converting csh variables for bash
setenv BASH_VAR $csh_var
bash -c 'echo $BASH_VAR'
# Calling csh from bash
csh -c 'echo $csh_variable'
# Mixed environment
# Use bash for scripting, csh for interactive
exec bash script.sh # Execute bash script
exec tcsh # Return to tcsh
The C Shell and its enhanced version tcsh represent an important chapter in Unix shell evolution, introducing many features that became standard in later shells. While csh is not recommended for complex scripting due to various limitations and inconsistencies, it remains valuable for interactive use, particularly for users who prefer its C-like syntax and specific features. Understanding csh is important for system administrators who encounter it in legacy systems and for users who appreciate its unique approach to command-line interaction. For modern shell scripting needs, however, POSIX-compliant shells like bash or more advanced shells like zsh are generally preferred.