Basic Shell Reference

Basic Shell Reference

A comprehensive reference guide to Unix shell commands.

Public Domain. No warranty provided; use at your own risk.
Some of the examples below may apply to a specific shell, such as BASH.
Most of them have been tested with Mac OS X using the Terminal.

Table of Contents

The Basics Control Structures More to come!

Back

The Basics

# ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
# THE BASICS
# ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

# Begin a shell file
# (This should be the first line of any shell script, including the "#")
#!/bin/sh

# Shell values
# csh = C Shell                (similar syntax to C language)
# sh = Bourne Shell            (basic shell)
# bash = Bourne-Again Shell    (used in Mac OS X)
# ksh = Korn Shell

# Shell script file format
# The basic shell script file format is a plain text file with
# Unicode (UTF-8) or 7-bit US-ASCII encoding and UNIX-style line breaks
# (ASCII character 10). One command may go on each line, or you can put
# multiple commands on a single line by separating them with semicolons ";".

# Comment lines
# Comment lines begin with a number sign "#". Blank lines are also ignored.

# Exit the script
# (placed here so this script does nothing if executed)
exit 0;

# Display a string of text to the output (such as the Terminal window)
echo "Hello world!"
echo -n "Hello world!"    # don't add a new line
printf "Hello world!" ""  # use a format string

# Strings and string literals may be combined
SOME_STRING="Hello"
echo $SOME_STRING" World!"

# Set, get, and delete variables
# Note that there can't be any whitespace around the equal sign.
# Space = comparison, no space = assignment.
# Also note that double-quoted strings are interpreted. In this case,
# $0 is replaced with the script path, and $FOO is replaced by
# the value of the variable FOO.
FOO="$0"
echo "$FOO"
unset FOO

# Insert output of a command
# In this example, the cat command is executed and the output
# is stored in the FOO variable.
FOO="$(cat)";

# Escape / wrap string literals
ls "$FILENAME" # FILENAME is now properly handled by ls, if it has any spaces
echo "\"yes\"" # echoes "yes" with double quotes
echo \"yes\"   # backslash makes next character behave as if quoted/escaped
echo "$0"      # double-quoted strings are interpreted by the shell
echo '$0'      # single-quoted strings are not. This echoes $0, literally
echo testing   # in some cases you don't have to escape a string literal

# To escape a single quote in a single quote string
echo 'It'\''s a beautiful day.'
echo 'Won'"t"'t you be my neighbor?'

# Export environment (global) variable
# Global variables are shared with any script called by this one.
export PATH="/usr/local/bin:$PATH" # or
PATH="/usr/local/bin:$PATH"; export PATH

# Check if environment variable is defined
# Returns 0 or 1.
DEFINED=`printenv | grep -c '^VARIABLE='`

# Increment a variable value by one
i=0;
((i++));
# or i=`expr $i + 1`;
# or ((i++)); / ((i+=1)); / ((i=i+1)); / i=$((i+1));

# Get user input
# printf doesn't add a new line.
printf 'Enter your name: '
read NAME
echo "Hello, $NAME."

# Get multi-argument user input, with a custom separator
# IFS is a system variable that sets the separator character.
printf "Type three numbers separated by 'q'. -> "
IFS="q"
read NUMBER1 NUMBER2 NUMBER3
echo "You said: $NUMBER1, $NUMBER2, $NUMBER3"

# Prompt for a yes or no response, exiting on no
read -p "Would you like to run the installer now? (Y/N): " response;
[ $response != 'y' ] && exit;

# Output a lot of text at once
# This saves a multi-line string literal to the file foo.c.
# Note that we define the "end of file" token, "EOF".
# This lets us write multiple lines, none of which are interpreted by the shell.
cat > foo.c << EOF
	#include <stdio.h>
	int main(int argc, char *argv[]){}
EOF

# Another EOF example, which runs an inline AppleScript on Mac.
# It counts the number of files on the desktop and sends the result to stdout
osascript -- << EOF
	tell app "Finder"
		set myDesktop to path to desktop folder as alias
		set theFiles to every item in myDesktop
		set num to the count of theFiles
		set output to ("Number of files on the desktop: " & num)
	end tell
	return the quoted form of output
EOF

# Basic file redirection
# > creates a file, >> appends to an existing file.
echo "a line of text" > MyFile
echo "an appended line of text" >> MyFile

# Pipes
# Pipes direct the output of one program to the input of another.
ls -l | grep 'rwx'
echo * | wc # list a count of all items in current folder

# File descriptor numbers:
# 0 is standard input (stdin)
# 1 is standard output (stdout)
# 2 is standard error (stderr)

# Combine stderr and stdout, and pipe to grep
ls -1 THISFILEDOESNOTEXIST 2>&1 | grep 'rwx'

# Send an error message to stderr
echo "a custom error message" 1>&2

# Get the last exit status with $?
ls mysillyfilename
if [ $? = 0 ] ; then
	echo "File exists."
fi

# Another quick way to test the last exit status
ls mysillyfilename && echo "File exists."

# Chaining execution
# && - if command to left succeeds (status 0), command to right executes
# || - if command to left fails (status != 0), command to right executes
# ! - executes command to the right of operator

# Date (use -u for UTC, and -j to avoid accidentally setting the time)
date # show date and time, like "Thu Feb 8 16:47:32 MST 2001"
date '+DATE: %m/%d/%y TIME: %H:%M:%S' # like "DATE: 02/08/01 TIME: 16:44:55"

# More date format examples:
date							# Default "Wed Aug 10 15:59:55 CDT 2016" (Local)
date -u '+%Y-%m-%d %H:%M:%S'	# SQL "2016-08-10 15:59:55" (UTC)
date -u '+%Y-%m-%d'				# SQL Date "2016-08-10" (UTC)
date -u '+%H:%M:%S'				# SQL Time "15:59:55" (UTC)
date '+%Y-%m-%dT%H:%M:%S%z'		# ISO 8601 (Local) "2016-08-10T16:16:16-0500"
date -u '+%Y-%m-%dT%H:%M:%S%z'	# ISO 8601 (UTC) "2016-08-10T21:17:20+0000"
date '+%-m/%-e/%y %-l:%M:%S %p'			# US Abbr "8/10/16 9:57:10 PM"
date '+%a %b %-d %Y %-l:%M:%S %p'		# US Short "Wed Aug 10 2016 9:56:10 PM"
date '+%A, %B %-d, %Y at %-l:%M:%S %p %Z'	# US Long
											# "Wednesday, August 10 2016 at
											# 4:58:57 PM CDT"
date '+%Y-%m-%d %-l:%M %p'		# US/SQL Hybrid "2016-08-10 1:00 PM" (Local)
											

# Note that even without zero-padding, some items may still be padded
# with spaces. To get around this, you need to strip repeating spaces
# using the "%-N" form or with sed like "date | sed 's/ //'

# Date Command Format String Tokens
# Date format string prefix - +
# Separators (optional) - /, :, -
# Disable padding for a token - %-N (where N is the token)
# Locale default - %c "Wed Aug 10 15:59:55 CDT 2016" (Local)
# Century - %C (or %cc) "01" (01-99)
# Year - %y "01" (01-99), %Y (or %ccyy) "0001" (0001-9999)
# Month - %mm "01" (01-12), %n (1-12), %b "Jan", %B "January"
# Day of Month - %d "01" (01-31), %e "1"
# Day of Year - %j "001" (001-366)
# Day of Week - %w (0-6, 0 = Sunday), %u (0-6, 0 = Monday)
# Weekday Name - %a "Wed" %A "Wednesday"
# Week of Year - %V (01-53), %U (Sunday first), %W (Monday first)
# Hours, Minutes, Seconds - %H, %M, %S (24-hour, two-digit, 0-61 seconds)
# 12-Hour - %l (12-hour, 1-digit), %L (12-hour, 2-digit)
# 24-Hour - %k (24-hour, 1 digit), %H (24-hour, 2-digit)
# AM/PM (locale-aware; may be blank) - %p (uppercase), %P (lowercase)
# Unix Timestamp - %s (seconds since 00:00:00 1970-01-01 UTC)
# Timezone - %z "-0500" (RFC-822-style offset), %Z "EDT" (or blank)
# Nanoseconds - %N (padded to 9 digits)
Back Top

Control Structures

# ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––————————
# CONTROL STRUCTURES
# ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––————————

# If statement (if... else... elif... fi)
if true; then
	ls
else
	echo 'true is false.'
elif false; then
	echo 'something else.'
fi

# Test conditions for if with "test" command.
# "[" is a shortcut for "test"; always put a space after it.
# Also remember to put spaces around the equal sign.
# Space = comparison, no space = assignment.
if [ "$FIRST_ARGUMENT" = "Silly" ] ; then # ...

# You can use the following operators within
# the above "test" statement brackets:
# ---------- Expression Operators ----------
# (exp), !exp, exp1 -a exp2, exp1 -o exp2 (true, false, and, or)
# ---------- String Operators ----------
# -n str, -z str, str = str, str != str (nonzero, zero, equal, not equal)
# ---------- Integer Operators ----------
# -eq, -ge, -gt, -le, -lt, -ne (==, >=, >, <=, <, !=; "int1 op int2")
# ---------- File Operators ----------
# -ef -nt -ot (same device & inode, newer, older; "file1 op file2")
# -b -c -d -e -f -g -G -h -k -L -O -p -r -s -S -t -u -w -x
# (block special, char special, directory, exists, document, set-group-ID,
# owned by effective group ID, symbolic link, sticky bit set, symbolic link,
# owned by effective user ID, named pipe, readable, nonzero size, socket,
# opens file descriptor on a terminal, set-user-ID bit set, writeable,
# searchable/executable; "op file")

# Switch statement
# (* means default value)
case $NUMBER in
	( '1' ) ALPHA='one' ;;
	( '2' ) ALPHA='two' ;;
	( '3' ) ALPHA='three' ;;
	( * ) ALPHA='other' ;;
esac

# While statement (while... do... done)
# (also break and continue keywords supported,
# with optional numbers after them)
while true; do
	ls; break;
done
while [ "x$FOO" != "x" ] ; do
    FOO="$(cat)";
done

# For statement (for... in... do... done; BASH-specific)
for i in *.JPG ; do
	echo $i
done

# Custom field separators (via special IFS variable)
# (for... in... do... is BASH-specific)
IFS=":"
LIST="a:b:c d"
for i in $LIST ; do
	echo $i
done
unset IFS # back to default (space/tab/newline, like IFS=" \t\n")

# Extended for loops (BASH/ZSH/SH-specific)
for (( i = 1 ; i <= $1 ; i++ )) ; do
	echo "I is $i"
done

# For maximum portability, use a while loop instead of for loops
i=1; while [ $i -le $1 ] ; do
    echo "I is $i"
    i=`expr $i '+' 1`
done

# Expressions (expr command)
# Value 1, operator (quoted), value 2.
# Returns 0 on true (success), 1 on false (failure).
# Operators: = != < > <= >= | &
echo $(expr "This is a test" '<' "I am a person");

# subroutines with local variables and return values
# (get executed in a separate shell)
# (exit keyword not supported in subs)
mysub(){
	local MYVAR
	MYVAR=123
	echo "Arg 1: $1"
	return $MYVAR
}
mysub "This is an arg"
echo "Subroutine returned $?"

# Basic user-defined function with a numeric return value
add_two_numbers(){
	FIRST_NUMBER=$1;
	SECOND_NUMBER=$2;
	RESULT=$(echo $FIRST_NUMBER'+'$SECOND_NUMBER | bc);
	return $RESULT;
}
echo add_two_numbers 8 9;

export -f fname		# Export a function
readonly -f fname	# Make a function readonly

# Include one script inside another (sourcing; bourne-specific)
# use the "." or "source" keywords (period is more portable)
. "/path/to/mysub.sh"

# Arrays
ARRAYNAME[0]="Value0"
ARRAYNAME[1]="Value1"
ARRAYNAME[2]="Value2"

# Array init shortcuts
set -A ARRAYNAME "Value0" "Value1" # Init array in ksh
ARRAYNAME=("Value0" "Value1") # Init array in bash

# Get array value
${ARRAYNAME[0]}
echo "First index: ${ARRAYNAME[0]}"

# Get all array values
${array_name[*]} # (expanded as "$1 $2 $3" with IFS delimiter)
${array_name[@]} # (expanded as "$1" "$2" "$3")

# Exit the script and return a numeric result code
# (0 typically means success, and 1 means error)
exit 0;

# Try to execute a statement, and on failure, echo a message and exit
# (the spaces within the braces are required)
echo "Testing." || { echo "Command failed."; exit 1; }

# Try to execute a statement, and on success, echo a message and exit
# (the spaces within the braces are required)
echo "Testing." && { echo "Command succeeded."; exit 0; }
Back Top