The shell uses the following environment variables.
CDPATH
A colon-separated list of directories used as a search path for the cd
builtin command.
If the target directory of the cd
command is specified as a relative path name, the cd
command first looks for the target directory in the current directory (.
). If the target is not found, the path names listed in the CDPATH
variable are searched consecutively until the target directory is found and the directory change is completed. If the target directory is not found, the current working directory is left unmodified. For example, the CDPATH
variable is set to /home/hemimorphite
, and four directories exist under /home/hemimorphite
, layouts
, posts
, assets
and vendors
. If you are in the /home/hemimorphite/posts
directory and type cd vendors
, you change directories to /home/hemimorphite/vendors
, even though you do not specify a full path.
HOME
The current user's home directory; the default for the cd
builtin command. The value of this variable is also used by tilde expansion (~
).
cd $HOME
# OR
cd ~
IFS
A list of characters that separate fields; used when the shell splits words as part of expansion.
The default value is a space, a tab, and a newline (IFS=$' \t\n'
).
You can print it with the following command:
cat -etv <<<"$IFS"
You should see something as follows on your Linux terminal:
^I$
$
The IFS
variable is commonly used with read
command, parameter expansions and command substitution.
In the read
command, if multiple variable-name arguments are specified, IFS
is used to split the line of input so that each variable gets a single field of the input. (The last variable gets all the remaining fields, if there are more fields than variables.) Any whitespace characters in IFS
will be trimmed from the beginning and end of the input line, even when only one variable is given.
# Using default IFS=$' \t\n'
[hemimorphite@ubuntu ~]$ read -r a b c <<< ' A B C'
[hemimorphite@ubuntu ~]$ echo "$a $b $c"
A B C
# Using a custom IFS value
[hemimorphite@ubuntu ~]$ IFS=: read -r user pwhash uid gid gecos home shell \
<<< 'root:*:0:0:System Administrator:/var/root:/bin/sh'
[hemimorphite@ubuntu ~]$ echo "$user $pwhash $uid $gid $gecos $home $shell"
root * 0 0 System Administrator /var/root /bin/sh
If IFS
contains a mixture of whitespace and non-whitespace characters then any non-whitespace IFS character or IFS whitespace characters (any sequence of one or more whitespace IFS characters count as single whitespace) acts as a single field delimiter. For example:
[hemimorphite@ubuntu ~]$ IFS=' ,'
[hemimorphite@ubuntu ~]$ sentence="This is a, simple, example"
[hemimorphite@ubuntu ~]$ printf 'word -> "%s" \n' $sentence
word -> "This"
word -> "is"
word -> "a"
word -> "simple"
word -> "example"
[hemimorphite@ubuntu ~]$ IFS=$' \t\n' read -r a b c \
<<< 'the plain gold ring'
[hemimorphite@ubuntu ~]$ echo "=$a= =$b= =$c="
=the= =plain= =gold ring=
The above example shows that splitting and delimiter-consolidation are not performed on the remaining part of a line when assigning excess fields to the last variable.
[hemimorphite@ubuntu ~]$ IFS=: read -r a b c \
<<< '1:2:::3::4'
[hemimorphite@ubuntu ~]$ echo "=$a= =$b= =$c="
=1= =2= =::3::4=
Note that out of the three consecutive colons which follow field 2, precisely one colon was removed in order to terminate field 2. The remaining two colons, as well as two more colons later on, were all left untouched, and assigned to variable c
verbatim.
OPTARG
The value of the option processed by the getopts
builtin.
Let's create a bash script called command.sh
[hemimorphite@ubuntu ~]$ cat command.sh
#!/bin/bash
# Parse command-line options
while getopts ":f:d:" flag; do
case $flag in
f) echo "The filename is: ${OPTARG}"
;;
d) echo "The directory is: ${OPTARG}"
esac
done
The Bash script utilizes the getopts
command to parse command-line options. It specifies two options, -f
and -d
in the optstring. As there is a colon (:) after both options, if triggered each of them requires an argument.
Inside the loop, a case
statement is used to check the currently processed option. If the option -f
is encountered, the script prints out the filename specified with the option using the special variable OPTARG
. Similarly, if the option -d
is found, the script displays the directory provided with the option using OPTARG
.
[hemimorphite@ubuntu ~]$ ./command.sh -f file1.txt -d /home hemimorphite
The filename is: file1.txt
The directory is: /home hemimorphite
OPTERR
OPTERR
controls if Bash displays errors generated by the getopts
builtin command. getopts
does not print errors if OPTERR
has a value of 0
. Value 1
enables the errors.
The default value is 1
.
OPTIND
The index of the next parameter/argument processed by the getopts
builtin.
[hemimorphite@ubuntu ~]$ cat command.sh
#!/bin/bash
while getopts "ab:c" flag; do
echo "$flag" "$OPTIND" "$OPTARG"
done
[hemimorphite@ubuntu ~]$ ./command.sh -ac -b value1
a 1
c 2
b 4 value1
In ./command.sh -ac -b value1
, arg1 is -ac
, arg2 is -b
, arg3 is value1
.
While processing option -a
, the next unprocessed option is -c
which is in arg1. So the index stored in OPTIND
is 1
. For the following option -c
, the next unprocessed option is -b
which is arg2. So the index stored in OPTIND
is 2
. Finally, for the option -b
, while processing option -b
, arg3 (value1
) is processed as an argument of option -b
. That's why OPTIND
stores 4
or the index of arg4.
[hemimorphite@ubuntu ~]$ ./command.sh -a -c -b value1
a 2
c 3
b 5 value1
In ./command.sh -a -c -b value1
, arg1 is -a
, arg2 is -c
, arg3 is -b
, arg4 is value1
.
While processing option -a
, the next unprocessed option is -c
which is in arg2. So the index stored in OPTIND
is 2
. For the following option -c
, the next unprocessed option is -b
which is arg3. So the index stored in OPTIND
is 3
. Finally, for the option -b
, while processing option -b
, arg4 (value1
) is processed as an argument of option -b
. That's why OPTIND
stores 5
or the index of arg5.
PATH
A colon-separated list of directories in which the shell looks for commands. This is the variable that tells the bash shell where to find different executable files and scripts. The shell will check the directories listed in the PATH
variable for the script you are trying to find.
Let's say you wrote a little shell script called hello
and have it located in a directory called /home/hemimorphite/bin
.
[hemimorphite@ubuntu ~/bin]$ cat hello
#!/bin/bash
echo Hello "$USER"
[hemimorphite@ubuntu ~/bin]$ chmod +x hello
Add /home/hemimorphite/bin
to the $PATH
variable with the following command:
[hemimorphite@ubuntu ~/bin]$ export PATH=$PATH:/home/hemimorphite/bin
You should now be able to execute the script anywhere on your system by just typing in its name, without having to include the full path as you type it.
[hemimorphite@ubuntu ~/bin]$ hello
Hello hemimorphite
Name of file to check for incoming mail.
MAILCHECK
defines the interval in seconds when the shell should check for mail. (default 60 seconds).
MAILPATH
List of filenames, separated by colons (:), to check for incoming mail.
Run the following command to install mail
sudo apt install mailutils
Let us create a new user named satella, echidna, and minerva using the useradd
command on Ubuntu:
[hemimorphite@ubuntu ~/]$ sudo useradd -s /bin/bash -d /home/satella/ -m -G sudo satella
[hemimorphite@ubuntu ~/]$ sudo passwd satella
[hemimorphite@ubuntu ~/]$ sudo useradd -s /bin/bash -d /home/echidna/ -m -G sudo echidna
[hemimorphite@ubuntu ~/]$ sudo passwd echidna
[hemimorphite@ubuntu ~/]$ sudo useradd -s /bin/bash -d /home/minerva/ -m -G sudo minerva
[hemimorphite@ubuntu ~/]$ sudo passwd minerva
Where,
-s /bin/bash
, set/bin/bash
as login shell of the new account-d /home/satella/
, set/home/satella/
as home directory of the new Ubuntu account-m
, create the user's home directory-G sudo
, make satella user can usesudo
command
Switch to user satella.
[hemimorphite@ubuntu ~/]$ sudo su - satella
[satella@ubuntu ~/]$
Use the echo
command to send an email without entering the interactive mode of the mail
command. Write the email body and pipe the echo
command output to the mail
command.
[satella@ubuntu ~/]$ echo "This is the email body" | mail -s "this is email subject" echidna, minerva
After 60 seconds (the value of MAILCHECK
), on echidna's or minerva's prompt press ENTER
and the prompt will print the message:
You have mail in /var/mail/echidna
Shell will use the value of MAIL
as the name of the file to check, unless MAILPATH
is set; in which case, the shell will check each file in the MAILPATH
list for new mail. You can use this mechanism to have the shell print a different message for each mail file: for each mail filename in MAILPATH
, append a question mark followed by the message you want printed.
You could define MAILPATH
to be:
MAILPATH="\
/usr/mail/satella/echidna?Mail from Echidna has arrived.:\
/usr/mail/satella/minerva?There is new mail from Paul."
The backslashes at the end of each line allow you to continue your command on the next line. Now, if you get mail from echidna, the shell will print:
Mail from Echidna has arrived.
You can also use the variable $_
in the message to print the name of the current mail file or execute a command $(date)
to displays the current date and time. For example:
MAILPATH="\
/usr/mail/satella/echidna?Mail from Echidna has arrived in $_ at $(date).:\
/usr/mail/satella/minerva?There is new mail from Paul in $_ at $(date)."