The shell uses the following environment variables.
: (a colon)
:
is a shell builtin command inherited from the Bourne Shell. It does nothing beyond expanding arguments and performing redirection and has return status zero. :
is a no-op operator similar to true
and false
.
The syntax of the :
command takes the following form:
: [arguments]
The example below illustrated how :
is used in parameter expansion by setting a default value combined with :
.
[hemimorphite@ubuntu ~]$ cat ./input.sh
#!/usr/bin/env bash
read -p "Enter your name: " name
: ${name:=Hemimorphite} # if the user entered an empty string
echo "$name"
[hemimorphite@ubuntu ~]$ ./input.sh
Enter your name:
Hemimorphite
If :
is omitted, the default value is passed and treated as a command.
[hemimorphite@ubuntu ~]$ cat ./input.sh
#!/usr/bin/env bash
read -p "Enter your name: " name
${name:=Hemimorphite}
echo "$name"
[hemimorphite@ubuntu ~]$ ./input.sh
Enter your name:
./input.sh: line 3: Hemimorphite: command not found
Hemimorphite
The usual way to do infinite loop in bash is using the true
command in a while
loop.
#!/usr/bin/env bash
while true
do
# ...
done
Alternatively, we can use :
instead of true
to create an infinite loop.
#!/usr/bin/env bash
while :
do
# ...
done
. (a period)
The dot command (.
) is a command used to execute commands from a file in the current shell. In Bash, the source
command is synonym to the dot command (.
)
The syntax of the .
command takes the following form:
. filename [arguments]
When you run an executable script as ./hello.sh
, the commands are run in a new subshell, while when run as . hello.sh
the current shell context will be used. This mean that the dot command will apply changes to your current shell.
Let's look at the simple example below.
#!/usr/bin/env bash
export A="hello world"
echo $A
When run as an executable using ./hello.sh
, the A
variable is not exported in your current shell and would just return an empty result.
[hemimorphite@ubuntu ~]$ ./hello.sh
hello world
[hemimorphite@ubuntu ~]$ echo $A
When run the same script with the dot command using . hello.sh
, your current shell context will be changed.
[hemimorphite@ubuntu ~]$ . hello.sh
hello world
[hemimorphite@ubuntu ~]$ echo $A
hello world
break
Exit from a for
, while
, until
, or select
loop.
The syntax of the break
command takes the following form:
break [n]
[n]
is an optional argument and must be greater than or equal to 1. When [n]
is provided, the n-th enclosing loop is exited. break 1
is equivalent to break
.
Here is an example of using the break
statement inside nested for
loops.
When the argument [n]
is not given, break
terminates the innermost enclosing loop. The outer loops are not terminated:
[hemimorphite@ubuntu ~]$ cat loop.sh
#!/usr/bin/env bash
for i in {1..3}; do
for j in {1..3}; do
if [[ $j -eq 2 ]]; then
break
fi
echo "j: $j"
done
echo "i: $i"
done
[hemimorphite@ubuntu ~]$ ./loop.sh
j: 1
i: 1
j: 1
i: 2
j: 1
i: 3
If you want to exit from the outer loop, use break 2
. Argument 2 tells break
to terminate the second enclosing loop:
[hemimorphite@ubuntu ~]$ cat loop.sh
#!/usr/bin/env bash
for i in {1..3}; do
for j in {1..3}; do
if [[ $j -eq 2 ]]; then
break 2
fi
echo "j: $j"
done
echo "i: $i"
done
[hemimorphite@ubuntu ~]$ ./loop.sh
j: 1
continue
Resume the next iteration of a for
, while
, until
, or select
loop.
The syntax of the continue
command takes the following form:
continue [n]
The [n]
argument is optional and can be greater than or equal to 1. When [n]
is given, the n-th enclosing loop is resumed. continue 1
is equivalent to continue
.
In the example below, once the current iterated item is equal to 9, the continue
statement will cause execution to return to the beginning of the loop and to continue with the next iteration.
[hemimorphite@ubuntu ~]$ cat loop.sh
#!/usr/bin/env bash
for i in {1..10}
do
if [[ $i == '9' ]]
then
continue
fi
echo "Number $i!"
done
[hemimorphite@ubuntu ~]$ ./loop.sh
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
Number: 6
Number: 7
Number: 8
Number: 10
If you want to continue from the outer loop, use continue 2
. Argument 2 tells continue
to continue the second enclosing loop:
[hemimorphite@ubuntu ~]$ cat loop.sh
#!/usr/bin/env bash
for i in {1..5}
do
for j in {1..5}
do
if [[ $j -eq 2 ]]
then
continue 2
fi
echo "j: $j"
done
echo "i: $i"
done
[hemimorphite@ubuntu ~]$ ./loop.sh
j: 1
j: 2
j: 3
i: 1
j: 1
j: 2
j: 3
i: 3
cd
The cd
command changes the working directory of the current shell execution environment to directory. If you specify directory as an absolute path name, beginning with /, this is the target directory. cd
assumes the target directory to be the name just as you specified it. If you specify directory as a relative path name, cd assumes it to be relative to the current working directory.
Two special symbols are also supported:
.
Represents the current directory..
Represents the parent of the current directory
The syntax of the cd
command takes the following form:
cd [-L|[-P [-e]] [directory]
If [directory]
is not supplied, the value of the HOME
shell variable is used. If the shell variable CDPATH
exists, it is used as a search path. If directory begins with a slash, CDPATH
is not used.
The -P
option means to not follow symbolic links: symbolic links are resolved while cd
is traversing directory and before processing an instance of ..
in directory. For example,
[hemimorphite@ubuntu ~]$ mkdir -p gallery/album/photos
[hemimorphite@ubuntu ~]$ ln -s gallery/album/photos myalbum
[hemimorphite@ubuntu ~]$ cd -P myalbum
[hemimorphite@ubuntu ~/gallery/album/photos]$ pwd
/home/hemimorphite/gallery/album/photos
By default, the -L
option is supplied, symbolic links in directory are resolved after cd
processes an instance of ..
in directory.
[hemimorphite@ubuntu ~]$ mkdir -p gallery/album/photos
[hemimorphite@ubuntu ~]$ ln -s gallery/album/photos myalbum
[hemimorphite@ubuntu ~]$ cd myalbum
[hemimorphite@ubuntu ~/myalbum]$ pwd
/home/hemimorphite/myalbum
If the -e
option is supplied with -P
and the current working directory cannot be successfully determined after a successful directory change, cd
will return an unsuccessful status.
[hemimorphite@ubuntu ~]$ mkdir -p gallery/album/photos
[hemimorphite@ubuntu ~]$ cd gallery/album/photos
[hemimorphite@ubuntu ~/gallery/album/photos]$ rmdir ../photos ../../album
[hemimorphite@ubuntu ~/gallery/album/photos]$ cd ..
cd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
[hemimorphite@ubuntu ~/gallery/album/photos/..]$ echo $?
0
[hemimorphite@ubuntu ~]$ mkdir -p gallery/album/photos
[hemimorphite@ubuntu ~]$ cd gallery/album/photos
[hemimorphite@ubuntu ~/gallery/album/photos]$ rmdir ../photos ../../album
[hemimorphite@ubuntu ~/gallery/album/photos]$ cd -Pe ..
cd: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
[hemimorphite@ubuntu ~/gallery/album/photos/..]$ echo $?
1
In the shell, the command cd -
is a special case that changes the current working directory to the previous working directory by exchanging the values of the variables PWD
and OLDPWD
.
In the following steps, the variable curpath
represents an intermediate value used to simplify the description of the algorithm used by cd
. There is no requirement that curpath
be made visible to the application.
-
If no directory operand is given and the
HOME
environment variable is empty or undefined, the default behavior is implementation-defined and no further steps shall be taken.
For example:
[hemimorphite@ubuntu ~]$ HOME= [hemimorphite@ubuntu ~]$ cd
-
If no directory operand is given and the
HOME
environment variable is set to a non-empty value, thecd
command shall behave as if the directory named in theHOME
environment variable was specified as the directory operand.
For example:
[hemimorphite@ubuntu ~]$ HOME=/home/hemimorphite [hemimorphite@ubuntu ~]$ cd
-
If the directory operand begins with a slash
/
character, setcurpath
to the operand and proceed to step 7 -
If the directory operand is
.
or..
, proceed to step 6 -
Starting with the first pathname in the colon-separated
:
pathnames ofCDPATH
if the pathname is non-null, test if the concatenation of that pathname, add a/
character if that pathname did not end with a/
character, and the directory operand names a directory. If the pathname is null, test if the concatenation of dot, a/
character, and the operand names a directory. In either case, if the resulting string names an existing directory, setcurpath
to that string and proceed to step 7. Otherwise, repeat this step with the next pathname inCDPATH
until all pathnames have been tested. - Set curpath to the directory operand.
-
If the
-P
option is in effect, proceed to step 10. Ifcurpath
does not begin with a/
character, setcurpath
to the string formed by the concatenation of the value ofPWD
, a/
character if the value ofPWD
did not end with a/
character, andcurpath
. -
The curpath value shall then be converted to canonical form as follows, considering each component from beginning to end, in sequence:
.
components and any/
characters that separate them from the next component shall be deleted.- For each dot-dot component, if there is a preceding component and it is neither root nor dot-dot, then:
- If the preceding component does not refer (in the context of pathname resolution with symbolic links followed) to a directory, then the
cd
command shall display an appropriate error message and no further steps shall be taken. - The preceding component, all
/
characters separating the preceding component from dot-dot, dot-dot, and all/
characters separating dot-dot from the following component (if any) shall be deleted.
- If the preceding component does not refer (in the context of pathname resolution with symbolic links followed) to a directory, then the
- An implementation may further simplify
curpath
by removing any trailing/
characters that are not also leading/
characters, replacing multiple non-leading consecutive/
characters with a single/
, and replacing three or more leading/
characters with a single/
. If, as a result of this canonicalization, the curpath variable is null, no further steps shall be taken.
-
If
curpath
is longer than {PATH_MAX} bytes (including the terminating null) and the directory operand was not longer than {PATH_MAX} bytes (including the terminating null), thencurpath
shall be converted from an absolute pathname to an equivalent relative pathname if possible. This conversion shall always be considered possible if the value ofPWD
, with a trailing/
added if it does not already have one, is an initial substring ofcurpath
. Whether or not it is considered possible under other circumstances is unspecified. Implementations may also apply this conversion ifcurpath
is not longer than {PATH_MAX} bytes or the directory operand was longer than {PATH_MAX} bytes. - The
cd
command shall then perform actions equivalent to thechdir()
function called withcurpath
as the path argument. If these actions fail for any reason, thecd
command shall display an appropriate error message and the remainder of this step shall not be executed. If the-P
option is not in effect, thePWD
environment variable shall be set to the value thatcurpath
had on entry to step 9 (i.e., before conversion to a relative pathname). If the-P
option is in effect, thePWD
environment variable shall be set to the string that would be output bypwd -P
. If there is insufficient permission on the new directory, or on any parent of that directory, to determine the current working directory, the value of thePWD
environment variable is unspecified.
If, during the execution of the above steps, the PWD
environment variable is set, the OLDPWD
environment variable shall also be set to the value of the old working directory.
When specifying a directory to change to, you can use either absolute or relative path names. The absolute or full path starts from the system root /
, and the relative path starts from your current directory.
By default, when you log into your Linux system, your current working directory is set to your home directory. Assuming that the Downloads
directory exists in your home directory, you can navigate to it by using the relative path to the directory:
[hemimorphite@ubuntu ~]$ cd Downloads
You can also navigate to the same directory by using its absolute path:
[hemimorphite@ubuntu ~]$ cd /home/hemimorphite/Downloads
On Unix-like operating systems, the current working directory is represented by a single dot (.). Two dots (..), one after the other, represent the parent directory or the directory immediately above the current one.
If you type cd .
, you will change into the current directory or, in other words, the command will do nothing.
Suppose you are currently in the /usr/local/share
directory. To switch to the /usr/local
directory (one level up from the current directory), you would type:
[hemimorphite@ubuntu /usr/local/share]$ cd ..
[hemimorphite@ubuntu /usr/local]$
To move two levels up to the /usr
directory, you type:
[hemimorphite@ubuntu /usr/local/share]$ cd ../../
[hemimorphite@ubuntu /usr]$
Let's say you are in the /usr/local/share
directory, and you want to switch to the /usr/local/src
. You can do that by typing:
[hemimorphite@ubuntu /usr/local/share]$ cd ../src
[hemimorphite@ubuntu /usr/local/src]$
To change back to the previous working directory, pass the dash (-) character as an argument to the cd
command:
[hemimorphite@ubuntu /usr/local/share]$ cd ../src
[hemimorphite@ubuntu /usr/local/src]$ cd -
[hemimorphite@ubuntu /usr/local/share]$
To navigate to your home directory, simply type cd
. Another way to return directly to your home directory is to use the tilde (~) character, as shown below:
[hemimorphite@ubuntu /usr/local/share]$ cd ~
[hemimorphite@ubuntu ~]$
For example, if you want to navigate to the Downloads
directory, which is inside your home directory, you would type:
[hemimorphite@ubuntu /usr/local/share]$ cd ~/Downloads
[hemimorphite@ubuntu ~/Downloads]$
You can also navigate to another user's home directory using the following syntax:
[hemimorphite@ubuntu /usr/local/share]$ cd ~satella
[hemimorphite@ubuntu /home/satella]$
If the directory you want to change to has spaces in its name, you should either surround the path with quotes or use the backslash (\) character to escape the space:
[hemimorphite@ubuntu ~]$ mkdir "hello world"
[hemimorphite@ubuntu ~]$ cd "hello world"
Or
[hemimorphite@ubuntu ~]$ mkdir "hello world"
[hemimorphite@ubuntu ~]$ cd hello\ world
eval
eval
command is used on a Unix or Linux system to execute the arguments as a shell command. The eval
command is helpful when you want to execute a Unix or Linux command that has been saved in a variable.
The syntax of the eval
command takes the following form:
eval [arguments]
The command or script that must be evaluated and run in this case is represented by [arguments]
. It may contain commands, variables, and even sophisticated expressions.
Storing a command in a variable is useful, especially when you want to store it with an option or flag appended to the command. In the following example, we will store the expr
command in a variable named command
:
[hemimorphite@ubuntu ~]$ var1=10
[hemimorphite@ubuntu ~]$ var2=20
[hemimorphite@ubuntu ~]$ command='expr $var1 + $var2'
[hemimorphite@ubuntu ~]$ eval $command
30
In the following example, the eval
command substitutes the date
command placed within a string stored in the command variable. eval
evaluates the string and executes the result:
[hemimorphite@ubuntu ~]$ command="echo \$(date)"
[hemimorphite@ubuntu ~]$ eval $command
Fri Jun 14 18:47:57 +07 2024
exec
The exec
command executes a shell command without creating a new process. Instead, it replaces the currently open shell operation.
The syntax of the exec
command takes the following form:
exec [-cl] [-a name] [command [arguments]]
If the -l
option is supplied, the shell places a dash at the beginning of the zeroth argument passed to command. So if we ran the following command:
exec -l tail -f /etc/passwd
Open a second terminal. Run the ps auwwx
command and it would produce the following output in the process list.
[hemimorphite@ubuntu ~]$ ps auwwx | grep tail
hemimor+ 6977 0.0 0.0 8404 1008 pts/0 Ss+ 22:03 0:00 -tail -f /etc/passwd
hemimor+ 7163 0.0 0.0 9212 2372 pts/1 S+ 22:23 0:00 grep --color=auto /etc/passwd
The -c
option causes the supplied command to run with a empty environment. Environmental variables like PATH
, are cleared before the command it run.
[hemimorphite@ubuntu ~]$ bash
[hemimorphite@ubuntu ~]$ ps auwwx | grep tail
SHELL=/bin/bash
SESSION_MANAGER=local/ubuntu:@/tmp/.ICE-unix/1259,unix/ubuntu:/tmp/.ICE-unix/1259
QT_ACCESSIBILITY=1
COLORTERM=truecolor
XDG_CONFIG_DIRS=/etc/xdg/xdg-cinnamon:/etc/xdg
XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
LANGUAGE=en_US
LC_ADDRESS=id_ID.UTF-8
LC_NAME=id_ID.UTF-8
[hemimorphite@ubuntu ~]$ exec -c printenv
[hemimorphite@ubuntu ~]$
The last option, -a [name]
, will pass name as the first argument to command. The command will still run as expected, but the name of the process will change.
exec -a HEMIMORPHITE tail -f /etc/passwd
Open a second terminal. Run the ps auwwx
command and it would produce the following output in the process list.
[hemimorphite@ubuntu ~]$ ps auwwx | grep HEMIMORPHITE
hemimor+ 6977 0.0 0.0 8404 1008 pts/0 Ss+ 22:03 0:00 HEMIMORPHITE -f /etc/passwd
hemimor+ 7163 0.0 0.0 9212 2372 pts/1 S+ 22:23 0:00 grep --color=auto HEMIMORPHITE
As you can see, exec
command passed HEMIMORPHITE as first argument to command, therefore it shows in the process list with that name.
The examples below demonstrate the behavior of the exec
command in the terminal.
Open the terminal and list the running processes
[hemimorphite@ubuntu ~]$ ps
PID TTY TIME CMD
8185 pts/0 00:00:00 bash
8192 pts/0 00:00:00 ps
The output shows the currently running Bash shell and the ps
command. The Bash shell has a unique PID.
To confirm, check the current process ID with:
[hemimorphite@ubuntu ~]$ echo $$
8185
The PID is the same as the output from the ps
command, indicating this is the currently running Bash process.
Now, run exec
followed by the sleep
command:
[hemimorphite@ubuntu ~]$ exec sleep 100
The sleep
command waits for 100 seconds.
Open another terminal tab, list all currently running processes and use grep
command to find sleep
process:
[hemimorphite@ubuntu ~]$ ps -ae | grep sleep
8185 pts/0 00:00:00 sleep
The PID for the process is the same as the Bash shell PID, indicating the exec
command replaced the Bash shell process.
The Bash session (terminal tab) closes when the one hundred seconds are complete and the process ends.
Now, we will see how exec
command works in Bash scripts.
Create a script file with the following content:
[hemimorphite@ubuntu ~]$ cat demo.sh
#!/bin/bash
while true
do
echo "1. Update "
echo "2. Upgrade "
echo "3. Exit"
read Input
case "$Input" in
1) exec sudo apt update ;;
2) exec sudo apt upgrade ;;
3) break
esac
done
Change the script permission to executable and run the script in the current environment to see the results:
[hemimorphite@ubuntu ~]$ chmod +x demo.sh
[hemimorphite@ubuntu ~]$ . demo.sh
1. Update
2. Upgrade
3. Exit
Executing the script with the source
command applies the script behavior to the current Bash shell. Use exec
to run Bash scripts within other programs for a clean exit.
The exec
command finds use in manipulating file descriptors for error logging in Bash scripts. The default Linux file descriptors are:
- stdin (0) - Standard in
- stdout (1) - Standard out
- stderr (2) - Standard error
Create a Bash script with the following content:
[hemimorphite@ubuntu ~]$ cat logging.sh
#!/bin/bash
# Create test.log file
touch test.log
# Save test.log to log_file variable
log_file="test.log"
# Redirect stdin to $log_file
exec 1>>$log_file
# Redirect stderr to the same place as stdin
exec 2>&1
echo "This line is added to the log file"
echo "And any other lines after"
eho "This line has an error and is logged as stderr"
Change the script permission to executable and run the script in the current environment to see the results:
[hemimorphite@ubuntu ~]$ chmod +x logging.sh
[hemimorphite@ubuntu ~]$ ./logging.sh
The script does not output any code. Instead, all the output logs to the test.log
file.
Use the cat
command to see the test.log
file contents:
[hemimorphite@ubuntu ~]$ cat test.log
This line is added to the log file
And any other lines after
./logging.sh: line 17: eho: command not found
exit
exit
command is used to exit the shell where it is currently running.
The syntax of the exit
command takes the following form:
exit [n]
It takes one parameter as [n]
and exits the shell with a return of status n
. If [n]
is not provided, then it simply returns the status of last command that is executed.
export
The export
command is used to export environmental variables that are accessible by all processes running in the current shell session and its child processes.
The syntax of the export
command takes the following form:
export [-fn] [-p] [name[=value]]
If the -f
option is supplied, the names musrt refer to shell functions.
[hemimorphite@ubuntu ~]$ example_function() {
echo "This is an example function."
}
[hemimorphite@ubuntu ~]$ export -f example_function
[hemimorphite@ubuntu ~]$ bash -c example_function
This is an example function.
If the -p
option is given or there is no option supplied, a list of names of all exported variables is displayed.
[hemimorphite@ubuntu ~]$ export -p
declare -x DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
declare -x DISPLAY=":0"
declare -x HOME="/home/hemimorphite"
declare -x HOSTTYPE="x86_64"
declare -x LANG="C.UTF-8"
declare -x LESSCLOSE="/usr/bin/lesspipe %s %s"
declare -x LESSOPEN="| /usr/bin/lesspipe %s"
declare -x LOGNAME="hemimorphite"
declare -x LS_COLORS="rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.webp=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:"
declare -x MOTD_SHOWN="update-motd"
declare -x NAME="DESKTOP-J3NDV0Q"
declare -x OLDPWD
declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
declare -x PULSE_SERVER="unix:/mnt/wslg/PulseServer"
declare -x PWD="/home/hemimorphite"
declare -x SHELL="/bin/bash"
declare -x SHLVL="1"
declare -x TERM="xterm-256color"
declare -x USER="hemimorphite"
declare -x WAYLAND_DISPLAY="wayland-0"
declare -x WSL2_GUI_APPS_ENABLED="1"
declare -x WSLENV=""
declare -x WSL_DISTRO_NAME="Ubuntu"
declare -x WSL_INTEROP="/run/WSL/247687_interop"
declare -x XDG_DATA_DIRS="/usr/local/share:/usr/share:/var/lib/snapd/desktop"
declare -x XDG_RUNTIME_DIR="/run/user/1000/"
The output lists all the variables used in the current shell session, and it is usually the same as running export
without options.
The -n
option removes the specified variables and functions from the list of exported variables.
In the following example, we remove the HOME
variable:
[hemimorphite@ubuntu ~]$ export -n HOME
[hemimorphite@ubuntu ~]$ export | grep HOME
[hemimorphite@ubuntu ~]$
If a variable name is followed by =value, the value of the variable is set to value.
[hemimorphite@ubuntu ~]$ export VARNAME="value"
[hemimorphite@ubuntu ~]$ printenv VARNAME
value
You also can assign a value to a variable first before exporting it using the export
command. For example:
[hemimorphite@ubuntu ~]$ x=100
[hemimorphite@ubuntu ~]$ export x
[hemimorphite@ubuntu ~]$ printenv x
100
getopts
The getopts
is used by shell scripts to parse positional parameters.
The syntax of the getopts
command takes the following form:
getopts optstring name [arg …]
optstring
contains the option characters to be recognized; if a character is followed by a colon, the option
is expected to have an argument, which should be separated from it by whitespace.The colon (:) and question mark (?) may not be used as option characters. Each time it is invoked, getopts
places the next option in the shell variable name
, initializing name if it does not exist, and the index of the next argument to be processed into the variable OPTIND
. OPTIND
is initialized to 1 each time the shell or a shell script is invoked. When an option requires an argument, getopts
places that argument into the variable OPTARG
. The shell does not reset OPTIND
automatically; it must be manually reset between multiple calls to getopts
within the same shell invocation if a new set of parameters is to be used.
Here's a simple example that demonstrates the basic usage of getopts
:
[hemimorphite@ubuntu ~]$ cat demo.sh
#!/bin/bash
while getopts "a:b" option; do
echo "Processing $option : OPTIND is $OPTIND"
case $option in
a)
echo "Option a is set with argument: $OPTARG"
;;
b)
echo "Option b is set"
;;
\?)
echo "Invalid option: -$OPTARG"
;;
esac
done
[hemimorphite@ubuntu ~]$ chmod +x demo.sh
[hemimorphite@ubuntu ~]$ ./demo.sh -b -a value1
Processing b : OPTIND is 2
Option b is set
Processing a : OPTIND is 4
Option a is set with argument: value1
[hemimorphite@ubuntu ~]$ ./demo.sh -a value1 -b
Processing a : OPTIND is 3
Option a is set with argument: value1
Processing b : OPTIND is 4
Option b is set
We mentioned above that the other variable that getopts
will set for you is the index of where you are up to in processing the options; this is the OPTIND
variable. It's the index of the next script argument to be processed, so if your script takes arguments: demo.sh -b -a value1
, then as it's processing -s
, the OPTIND
is 2, because the next thing it will process will be the 2nd argument (-a
). When it's processing -a value1
, OPTIND
is 4, because value1
is the 3rd script argument and the next index is 4.
When getopts
reaches the end of the options, it exits with a status value of 1. It also sets name to the character ?
and sets OPTIND
to the index of non-option argument. getopts
recognizes the end of the options by any of the following situations:
- Finding an option that require an argument but not supply with an argument
- Finding an option that doesn't start with -
- Encountering an error (for example, an unrecognized option letter)
If an invalid option is seen or a required argument of an option is not found, a question mark (?
>) is placed in name
and, prints an error message and unsets OPTARG
.
[hemimorphite@ubuntu ~]$ cat demo.sh
#!/bin/bash
while getopts "a:b" option; do
echo "Processing $option : OPTIND is $OPTIND"
case $option in
a)
echo "Option a is set with argument: $OPTARG"
;;
b)
echo "Option b is set"
;;
\?)
echo "Invalid option: -$OPTARG"
;;
esac
done
[hemimorphite@ubuntu ~]$ chmod +x demo.sh
[hemimorphite@ubuntu ~]$ ./demo.sh -a
./demo.sh: option requires an argument -- a
Processing ? : OPTIND is 2
Invalid option: -
[hemimorphite@ubuntu ~]$ ./demo.sh -z
./demo.sh: illegal option -- z
Processing ? : OPTIND is 2
Invalid option: -
If the first character of optstring
is a colon, silent error reporting is used.
If an invalid option is seen and silent error reporting is used, a question mark (?
>) is placed in name
and, the option character found is placed in OPTARG
and no error message is printed.
If a required argument of an option is not found and silent error reporting is used, then a colon (:
) is placed in name
and OPTARG
is set to the option character found.
[hemimorphite@ubuntu ~]$ cat demo.sh
#!/bin/bash
while getopts ":a:b" option; do
echo "Processing $option : OPTIND is $OPTIND"
case $option in
a)
echo "Option a is set with argument: $OPTARG"
;;
b)
echo "Option b is set"
;;
:)
echo "Argument missing"
;;
\?)
echo "Invalid option: -$OPTARG"
;;
esac
done
[hemimorphite@ubuntu ~]$ chmod +x demo.sh
[hemimorphite@ubuntu ~]$ ./demo.sh -a
Processing : : OPTIND is 2
Argument missing
[hemimorphite@ubuntu ~]$ ./demo.sh -z
Processing ? : OPTIND is 2
Invalid option: -z
hash
The hash
command affects the way the current shell remembers a command's path name, either by adding a path name to a list or purging the contents of the list.
The syntax of the hash
command takes the following form:
hash [-r] [-p filename] [-dt] [name]
When we run any commands or programs in the Linux shells, it records the location of the binary of these commands in a hash table.
The commands are found by searching through the directories listed in PATH
.
To list the entries in the hash table, we can run the hash
command without any arguments:
[hemimorphite@ubuntu ~]$ hash
hash: hash table empty
Since we haven't run any commands, there are no entries in the hash table.
[hemimorphite@ubuntu ~]$ ls >/dev/null
[hemimorphite@ubuntu ~]$ ls >/dev/null
[hemimorphite@ubuntu ~]$ which ls >/dev/null
[hemimorphite@ubuntu ~]$ hash
hits command
1 /usr/bin/which
2 /usr/bin/ls
We can run the hash command to add commands into the hash table without running it.
[hemimorphite@ubuntu ~]$ hash whoami grep xargs
[hemimorphite@ubuntu ~]$ hash
hits command
0 /usr/bin/grep
0 /usr/bin/whoami
0 /usr/bin/xargs
The hash
command resets the table when we supply the -r
option:
[hemimorphite@ubuntu ~]$ hash whoami grep xargs
[hemimorphite@ubuntu ~]$ hash
hits command
0 /usr/bin/grep
0 /usr/bin/whoami
0 /usr/bin/xargs
[hemimorphite@ubuntu ~]$ hash -r
[hemimorphite@ubuntu ~]$ hash
hash: hash table empty
We can remove specific commands from the table using the -d
option followed by the command name.
[hemimorphite@ubuntu ~]$ ls >/dev/null
[hemimorphite@ubuntu ~]$ ls >/dev/null
[hemimorphite@ubuntu ~]$ which ls >/dev/null
[hemimorphite@ubuntu ~]$ hash -d ls
[hemimorphite@ubuntu ~]$ hash
hits command
1 /usr/bin/which
The hash
command provides us a way to set the path of commands manually using the –p
option. We specify the -p
option followed by the path to the binary and then the command name we want to associate it with.
[hemimorphite@ubuntu ~]$ hash -p /usr/bin/date another-date
[hemimorphite@ubuntu ~]$ another-date
Sat Jun 15 07:17:01 PM WIB 2024
The hash
command provides us a way to display the lists of commands in the hash table using the –l
option.
[hemimorphite@ubuntu ~]$ ls
[hemimorphite@ubuntu ~]$ mkdir example
[hemimorphite@ubuntu ~]$ rmdir example
[hemimorphite@ubuntu ~]$ touch file
[hemimorphite@ubuntu ~]$ rm file
[hemimorphite@ubuntu ~]$ hash -l
builtin hash -p /usr/bin/ls ls
builtin hash -p /usr/bin/mkdir mkdir
builtin hash -p /usr/bin/rmdir rmdir
builtin hash -p /usr/bin/touch touch
builtin hash -p /usr/bin/rm rm
The hash
command doesn't report any shell built-in commands.
[hemimorphite@ubuntu ~]$ echo hello
hello
[hemimorphite@ubuntu ~]$ pwd
/home/hemimorphite
[hemimorphite@ubuntu ~]$ hash
hash: hash table empty
pwd
The pwd
(print working directory) command is used to displays the full pathname of the current directory.
The syntax of the pwd
command takes the following form:
pwd [-LP]
The -L
option is used to display the logical current directory. This means it shows the path you used to get to the directory, even if it involves symbolic links. The default behavior of pwd
command is the same as pwd -L
.
[hemimorphite@ubuntu ~]$ ln -s /var/log link_to_log
[hemimorphite@ubuntu ~]$ cd link_to_log
[hemimorphite@ubuntu ~/link_to_log]$ pwd -L
/home/hemimorphite/link_to_log
When we use pwd -L
, it returns /home/hemimorphite/link_to_log
, which is the logical path we used.
The -P
option is used to display the physical current directory. This means it shows the actual location of the directory, ignoring symbolic links.
[hemimorphite@ubuntu ~]$ ln -s /var/log link_to_log
[hemimorphite@ubuntu ~]$ cd link_to_log
[hemimorphite@ubuntu ~/link_to_log]$ pwd -P
/var/log
After navigating to link_to_log
, when we use pwd -P
, it returns /var/log
, which is the actual location of the directory.
readonly
The readonly
command is used to mark shell variables and functions as unchangeable. Once a variable or function is set as readonly, its value or function definition cannot be changed or unset.
The syntax of the readonly
command takes the following form:
readonly [-aAf] [-p] [name[=value]] …
The readonly
command without option is used to mark shell variables as readonly or unchangeable.
[hemimorphite@ubuntu ~]$ var1="Initial value"
[hemimorphite@ubuntu ~]$ readonly var1
[hemimorphite@ubuntu ~]$ var1="New value"
bash: var1: readonly variable
The -f
option is used to mark shell functions as readonly or unchangeable.
[hemimorphite@ubuntu ~]$ func1() {
> echo "This function is readonly"
> }
[hemimorphite@ubuntu ~]$ readonly -f func1
[hemimorphite@ubuntu ~]$ func1() {
> echo "Change function output"
> }
bash: func1: readonly function
The -a
option is used to mark indexed array variables as readonly or unchangeable.
[hemimorphite@ubuntu ~]$ declare -a countries
[hemimorphite@ubuntu ~]$ countries=("India" "France" "United Kingdom")
[hemimorphite@ubuntu ~]$ readonly -a countries
[hemimorphite@ubuntu ~]$ countries=("Japan" "Spanyol" "United State")
bash: countries: readonly variable
The -A
option is used to mark associative array variables as readonly or unchangeable.
[hemimorphite@ubuntu ~]$ declare -A country_capitals
[hemimorphite@ubuntu ~]$ country_capitals=(["India"]="New Delhi" ["France"]="Paris" ["United Kingdom"]="London")
[hemimorphite@ubuntu ~]$ readonly -A country_capitals
[hemimorphite@ubuntu ~]$ country_capitals=(["Japan"]="Tokyo" ["Spanyol"]="Madrid" ["United State"]="Washington")
bash: country_capitals: readonly variable
The -p
option is used to display the list of all readonly variables.
[hemimorphite@ubuntu ~]$ readonly -p
declare -r BASHOPTS="checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote:force_fignore:globasciiranges:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath"
declare -ar BASH_VERSINFO=([0]="5" [1]="1" [2]="16" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")
declare -ir EUID="1000"
declare -ir PPID="260303"
declare -r SHELLOPTS="braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor"
declare -ir UID="1000"
The -f
option is also used to display the list of all readonly functions.
[hemimorphite@ubuntu ~]$ func1() {
> echo "This function is readonly"
> }
[hemimorphite@ubuntu ~]$ readonly -f func1
[hemimorphite@ubuntu ~]$ readonly -f
func1 ()
{
echo "This function is readonly"
}
declare -fr func1
return
The return
command is used in the script to return the value called in the function. The return
command is always used in the function, if used outside the function it has no effect. This command stops the execution of the function where it is used.
The syntax of the return
command takes the following form:
return [n]
The return
command takes a parameter [n]
, if n is mentioned then it returns [n]
and if n is not mentioned then it returns the status of the last command executed within the function or script. n can only be a numeric value.
The special variable $?
is used to hold the return value and the status of last executed command.
[hemimorphite@ubuntu ~]$ add() {
> add=$(($1+$2))
> return $add
> }
[hemimorphite@ubuntu ~]$ add 25 26
[hemimorphite@ubuntu ~]$ echo $?
51
shift
The shift
command is used to shift the positional parameters (such as arguments passed to a bash script) to the left, putting each parameter in a lower position.
The syntax of the shift
command takes the following form:
shift [n]
The shift
command takes a parameter [n]
, if [n]
is mentioned then the current positional parameters are shifted left [n]
times. If [n]
is not specified, the default value of n is 1. So the commands shift 1
and shift
(with no argument) do the same thing
If a parameter is shifted to a position with a number less than 1, its value is discarded. So the command shift
always discards the previous value of $1
, and shift 2
always discards the previous values of $1
and $2
.
The special positional parameter $0
is excluded from all shift operations, and never modified by the shift
command.
Parameters with a number 10 or greater can be referenced by putting the number in brackets, for example ${10}
, ${11}
, or ${12345}
.
Bash keeps track of the total number of positional parameters. This number is stored in the special shell variable $#
.
The value of $#
decreases by n every time you run shift
.
You can pass arguments to a bash script by typing them after the script's name when running it. Each argument should be separated by a space.
Inside the script, you can access these arguments using special variables. $1
represents the first argument, $2
the second, and so on. Let's look at an example:
[hemimorphite@ubuntu ~]$ cat demo.sh
#!/bin/bash
echo 1: $1
echo 1: $2
[hemimorphite@ubuntu ~]$ chmod +x demo.sh
[hemimorphite@ubuntu ~]$ ./demo.sh one two
1: one
1: two
You will encounter situations that require more than just $1
, $2
, etc. Bash provides shift
command to help you manage these scenarios.
[hemimorphite@ubuntu ~]$ cat demo.sh
#!/bin/bash
USAGE="usage: $0 arg1 arg2 ... argN"
if (( $# == 0 ))
then
echo "$USAGE"
exit 1
fi
n=1
print "The arguments to the script are:"
while (($#))
do
echo $n: $1
n=$((n+1))
shift
done
[hemimorphite@ubuntu ~]$ chmod +x demo.sh
[hemimorphite@ubuntu ~]$ ./demo.sh one two three four five six
The arguments to the script are:
1: one
2: two
3: three
4: four
5: five
6: six
times
The shift
command is used to print out the user and system times used by the shell and its children.
trap
The trap
command is used to catch any supported signal and react upon it.
The syntax of the trap
command takes the following form:
trap [-lp] [arg] [sigspec …]
If arg
is absent (and there is a single sigspec
) or equal to -, each specified signal's disposition is reset to the value it had when the shell was started. For example:
trap - SIGINT SIGABRT
If arg
is the null string, then the signal specified by each sigspec
is ignored by the shell; in other words, the signal specified by each sigspec
is disabled.
trap "" SIGINT SIGABRT
The -l
option causes the shell to print a list of all the signals and their numbers.
[hemimorphite@ubuntu ~]$ trap -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
The trap -l
command doesn't display signals 32 and 33 in the output because they aren't supported on Linux.
The -p
option is used to display the trap commands.
[hemimorphite@ubuntu ~]$ trap "echo SIGINT terminated the process" SIGINT
[hemimorphite@ubuntu ~]$ trap "echo SIGTERM terminated the process" SIGTERM
[hemimorphite@ubuntu ~]$ trap -p
trap -- 'echo SIGINT terminated the process' SIGINT
trap -- 'echo SIGTERM terminated the process' SIGTERM
[hemimorphite@ubuntu ~]$ trap -p SIGINT
trap -- 'echo SIGINT terminated the process' SIGINT
[hemimorphite@ubuntu ~]$ trap - SIGINT SIGTERM
If a sigspec
is 0
or EXIT
, arg
is executed when the shell or subshell exits.
[hemimorphite@ubuntu ~]$ cat demo.sh
#!/bin/bash
# this executes when the subshell exits
trap "echo Exiting subshell..." EXIT
[hemimorphite@ubuntu ~]$ chmod +x demo.sh
[hemimorphite@ubuntu ~]$ ./demo.sh
Exiting subshell...
[hemimorphite@ubuntu ~]$ cat demo.sh
#!/bin/bash
# this executes when the shell exits
trap "echo Exiting shell..." EXIT
exit
[hemimorphite@ubuntu ~]$ chmod +x demo.sh
[hemimorphite@ubuntu ~]$ . demo.sh
Exiting shell...
[hemimorphite@ubuntu ~]$ trap - EXIT
If a sigspec
is RETURN
, the command arg
is executed each time the shell script finishes executing by the .
or source
builtins.
[hemimorphite@ubuntu ~]$ cat demo.sh
#!/bin/bash
# this executes when the script finishes executing
trap "echo Returning..." RETURN
[hemimorphite@ubuntu ~]$ . demo.sh
Returning...
[hemimorphite@ubuntu ~]$ trap - RETURN
If a sigspec
is DEBUG
, the command arg
is executed before every simple command, for
command, case
command, select
command, every arithmetic for command, and before the first command executes in a shell function.
[hemimorphite@ubuntu ~]$ cat demo.sh
#!/bin/bash
trap "echo Executing..." DEBUG
echo Hello World
whoami
which echo
[hemimorphite@ubuntu ~]$ ./demo.sh
Executing...
Hello World
Executing...
hemimorphite
Executing...
/usr/bin/echo
If a sigspec
is ERR
, the command arg
is executed whenever a pipeline (which may consist of a single simple command), a list, or a compound command returns a non-zero exit status. The ERR
trap is not executed if the failed command is part of the command list immediately following an until
or while
keyword, part of the test following the if
or elif
reserved words, part of a command executed in a &&
or ||
list except the command following the final &&
or ||
, any command in a pipeline but the last, or if the command's return status is being inverted using !
. These are the same conditions obeyed by the errexit
(-e
) option.
[hemimorphite@ubuntu ~]$ cat demo.sh
#!/bin/bash
trap "echo An error occurred." ERR
# unknown command
getcommand
[hemimorphite@ubuntu ~]$ ./demo.sh
./demo.sh: line 6: getcommand: command not found
An error occurred.
We can use the trap
command to intercept signals so that we can handle them.
We can set and invoke handlers for any and all available signals
We can even prevent the default action for all signals except SIGKILL
and SIGSTOP
:
[hemimorphite@ubuntu ~]$ cat demo.sh
#!/bin/bash
trap "echo 'sending SIGHUP signal'" 1
trap "echo 'sending SIGINT signal'" 2
trap "echo 'sending SIGQUIT signal'" 3
trap "echo 'sending SIGILL signal'" 4
trap "echo 'sending SIGTRAP signal'" 5
trap "echo 'sending SIGABRT signal'" 6
trap "echo 'sending SIGBUS signal'" 7
trap "echo 'sending SIGFPE signal'" 8
#trap "echo 'sending SIGKILL signal'" 9
trap "echo 'sending SIGUSR1 signal'" 10
trap "echo 'sending SIGSEGV signal'" 11
trap "echo 'sending SIGUSR2 signal'" 12
trap "echo 'sending SIGPIPE signal'" 13
trap "echo 'sending SIGALRM signal'" 14
trap "echo 'sending SIGTERM signal'" 15
trap "echo 'sending SIGSTKFLT signal'" 16
trap "echo 'sending SIGCHLD signal'" 17
trap "echo 'sending SIGCONT signal'" 18
#trap "echo 'sending SIGSTOP signal'" 19
trap "echo 'sending SIGTSTP signal'" 20
trap "echo 'sending SIGTTIN signal'" 21
trap "echo 'sending SIGTTOU signal'" 22
trap "echo 'sending SIGURG signal'" 23
trap "echo 'sending SIGXCPU signal'" 24
trap "echo 'sending SIGXFSZ signal'" 25
trap "echo 'sending SIGVTALRM signal'" 26
trap "echo 'sending SIGPROF signal'" 27
trap "echo 'sending SIGWINCH signal'" 28
trap "echo 'sending SIGIO signal'" 29
trap "echo 'sending SIGPWR signal'" 30
trap "echo 'sending SIGTSTP signal'" 31
[hemimorphite@ubuntu ~]$ chmod +x demo.sh
[hemimorphite@ubuntu ~]$ . demo.sh
[hemimorphite@ubuntu ~]$ kill -SIGHUP $$
sending SIGHUP signal
[hemimorphite@ubuntu ~]$ kill -SIGINT $$
sending SIGINT signal
[hemimorphite@ubuntu ~]$ kill -SIGQUIT $$
sending SIGQUIT signal
[hemimorphite@ubuntu ~]$ kill -SIGILL $$
sending SIGILL signal
[hemimorphite@ubuntu ~]$ kill -SIGTRAP $$
sending SIGTRAP signal
[hemimorphite@ubuntu ~]$ kill -SIGABRT $$
sending SIGABRT signal
[hemimorphite@ubuntu ~]$ kill -SIGBUS $$
sending SIGBUS signal
[hemimorphite@ubuntu ~]$ kill -SIGFPE $$
sending SIGFPE signal
[hemimorphite@ubuntu ~]$ kill -SIGUSR1 $$
sending SIGUSR1 signal
[hemimorphite@ubuntu ~]$ kill -SIGSEGV $$
sending SIGSEGV signal
[hemimorphite@ubuntu ~]$ kill -SIGUSR2 $$
sending SIGUSR2 signal
[hemimorphite@ubuntu ~]$ kill -SIGPIPE $$
sending SIGPIPE signal
[hemimorphite@ubuntu ~]$ kill -SIGALRM $$
sending SIGALRM signal
[hemimorphite@ubuntu ~]$ kill -SIGTERM $$
sending SIGTERM signal
[hemimorphite@ubuntu ~]$ kill -SIGSTKFLT $$
sending SIGSTKFLT signal
[hemimorphite@ubuntu ~]$ kill -SIGCHLD $$
sending SIGCHLD signal
[hemimorphite@ubuntu ~]$ kill -SIGCONT $$
sending SIGCONT signal
[hemimorphite@ubuntu ~]$ kill -SIGTSTP $$
sending SIGTSTP signal
[hemimorphite@ubuntu ~]$ kill -SIGTTIN $$
sending SIGTTIN signal
[hemimorphite@ubuntu ~]$ kill -SIGTTOU $$
sending SIGTTOU signal
[hemimorphite@ubuntu ~]$ kill -SIGURG $$
sending SIGURG signal
[hemimorphite@ubuntu ~]$ kill -SIGXCPU $$
sending SIGXCPU signal
[hemimorphite@ubuntu ~]$ kill -SIGXFSZ $$
sending SIGXFSZ signal
[hemimorphite@ubuntu ~]$ kill -SIGVTALRM $$
sending SIGVTALRM signal
[hemimorphite@ubuntu ~]$ kill -SIGPROF $$
sending SIGPROF signal
[hemimorphite@ubuntu ~]$ kill -SIGWINCH $$
sending SIGWINCH signal
[hemimorphite@ubuntu ~]$ kill -SIGIO $$
sending SIGIO signal
[hemimorphite@ubuntu ~]$ kill -SIGPWR $$
sending SIGPWR signal
[hemimorphite@ubuntu ~]$ kill -SIGTSTP $$
sending SIGTSTP signal
[hemimorphite@ubuntu ~]$ trap - SIGHUP SIGINT SIGQUIT SIGILL SIGTRAP SIGABRT SIGBUS SIGFPE SIGUSR1 SIGSEGV SIGUSR2 SIGPIPE SIGALRM SIGTERM SIGSTKFLT SIGCHLD SIGCONT SIGTSTP SIGTTIN SIGTTOU SIGURG SIGXCPU SIGXFSZ SIGVTALRM SIGPROF SIGWINCH SIGIO SIGPWR SIGTSTP
umask
The umask
command is used to set default permissions for files or directories the user creates.
The syntax of the umask
command takes the following form:
umask [-p] [-S] [mode]
In Linux, each file is associated with an owner and a group and assigned with permission access rights for three different classes of users:
- The file owner
- The group members
- Everyone else
There are three permissions types that apply to each class:
- The read permission
- The write permission
- The execute permission
The following example shows the permissions for a directory:
drwxr-xr-x 12 hemimorphite hemimorphite 4.0K Jun 16 20:51 dirname
|[-][-][-] [----------] [----------]
| | | | | |
| | | | | +----> Group
| | | | +----------------> Owner
| | | +----------------------------> Others Permissions
| | +-------------------------------> Group Permissions
| +----------------------------------> Owner Permissions
+------------------------------------> File Type
The first character represents the file type which can be a regular file (-), a directory (d), a symbolic link (l), or any other special type of file.
Character r
with an octal value of 4
stands for read
, w
with an octal value of 2
for write
, x
with an octal value of 1
for execute
permission, and (-
) with an octal value of 0
for no permissions.
If we represent the file permissions using a numeric notation, we will come up to the number 755
:
- Owner:
rwx
=4+2+1
=7
- Group:
r-x
=4+0+1
=5
- Other:
r-x
=4+0+1
=5
The first digit represents the special permissions, and if it is omitted, it means that no special permissions are set on the file. In the example above 755
is the same as 0755
. The first digit can be a combination of 4
for setuid
, 2
for setgid
, and 1
for Sticky Bit.
On Linux systems, the default creation permissions are 666
for files, which gives read and write permission to user, group, and others, and to 777
for directories, which means read, write and execute permission to user, group, and others. By default, Linux does not allow a file to be created with execute permissions.
The default creation permissions can be modified using the umask
command.
umask
affects only the current shell environment. On most Linux distributions, the umask
value is set in the pam_umask.so
or /etc/profile
file.
To view the current mask value:
[hemimorphite@ubuntu ~]$ umask
022
The umask
value contains the permission bits that will NOT be set on the newly created files and directories.
Once we get the umask
value, that is 022
, we can calculated the permissions for:
- Files:
666 - 022 = 644
(the default creation permissions for file – umask value = the permissions for file). The owner can read and modify the files. Group and others can only read the files. - Directories:
777 - 022 = 755
(the default creation permissions for drectory – umask value = the permissions for drectory). The owner cancd
into the directory, and list, read, modify, create or delete the files in the directory. Group and others cancd
into the directory and list and read the files.
If the -S
option is supplied without a mode
argument, the mask is printed in a symbolic format.
[hemimorphite@ubuntu ~]$ umask -S
u=rwx,g=rx,o=rx
If the -p
option is supplied, and mode
is omitted, the output is in a form that may be reused as input.
[hemimorphite@ubuntu ~]$ umask -p
umask 0022
unset
The unset
is used to unset or undefine values and attributes of variables and functions.
The syntax of the unset
command takes the following form:
unset [-fnv] [name]
If the -v
option is given, each name
refers to a shell variable and that variable is removed.
[hemimorphite@ubuntu ~]$ varname="hemimorphite blog"
[hemimorphite@ubuntu ~]$ echo $varname
hemimorphite blog
[hemimorphite@ubuntu ~]$ unset -v varname
[hemimorphite@ubuntu ~]$ echo $varname
[hemimorphite@ubuntu ~]$
If the -f
option is given, the names refer to shell functions, and the function definition is removed.
[hemimorphite@ubuntu ~]$ getname() {
> echo "hemimorphite blog"
> }
[hemimorphite@ubuntu ~]$ getname
hemimorphite blog
[hemimorphite@ubuntu ~]$ unset -f getname
[hemimorphite@ubuntu ~]$ getname
[hemimorphite@ubuntu ~]$
If the name
is a variable with the nameref
attribute, name
will be unset rather than the variable it references.
[hemimorphite@ubuntu ~]$ var=blog
[hemimorphite@ubuntu ~]$ declare -n varnameref=${var}name
[hemimorphite@ubuntu ~]$ varnameref="hemimorphite blog"
[hemimorphite@ubuntu ~]$ echo $blogname
hemimorphite blog
[hemimorphite@ubuntu ~]$ echo $varnameref
hemimorphite blog
[hemimorphite@ubuntu ~]$ unset -n varnameref
[hemimorphite@ubuntu ~]$ echo $blogname
hemimorphite blog
[hemimorphite@ubuntu ~]$ echo $varnameref
[hemimorphite@ubuntu ~]$
-n
option has no effect if the -f
option is supplied.
If no options are supplied, each name
refers to a variable or refers to a function; is removed.
Readonly variables and functions can't be unset.
[hemimorphite@ubuntu ~]$ readonly blogname="hemimorphite"
[hemimorphite@ubuntu ~]$ unset blogname
-bash: unset: blogname: cannot unset: readonly variable
test
The test
command compares one element against another and returns true or false.
The syntax of the test
command takes the following form:
test expr
Or
[ expr ]
test
exits with the status determined by expr
. Placing the expr
between square brackets ([ and ]) is the same as testing the expr
with test
. To see the exit status at the command prompt, echo
the value $?
A value of 0
means the expression evaluated as true
, and a value of 1
means the expression evaluated as false
.
Expressions of test
command take the following forms:
Expression | Description | Example |
---|---|---|
expression
|
expression is true
|
|
! expression
|
expression is false
|
|
expression1 -a expression2
|
both expression1 and expression2 are true
|
|
expression1 -o expression2
|
either expression1 or expression2 is true |
|
-n string
|
the length of string is nonzero |
|
string
|
equivalent to -n string
|
|
-z string
|
the length of string is zero |
|
string1 = string2
|
the strings are equal |
|
string1 != string2
|
the strings are not equal |
|
integer1 -eq integer2
|
integer1 equals integer2
|
|
integer1 -ge integer2
|
integer1 is greater than or equal to integer2
|
|
integer1 -gt integer2
|
integer1 is greater than integer2
|
|
integer1 -le integer2
|
integer1 is less than or equal to integer2
|
|
integer1 -lt integer2
|
integer1 is less than integer2
|
|
integer1 -ne integer2
|
integer1 is not equal to integer2
|
|
file1 -ef file2
|
file1 and file2 have the same device and inode (index node) numbers. The following metadata exists in an inode:
|
|
file1 -nt file2
|
file1 is newer (modification date) than file2
|
|
file1 -ot file2
|
file1 is older (modification date) than file2
|
|
-b file
|
file exists and is block special (block device). A block special file acts as a direct interface to a block device. A block device is any device which performs data I/O in units of blocks.Examples of block special files:
|
|
-c file
|
file exists and is character special. A character special file is similar to a block device, but data is written one character (eight bits, or one byte) at a time.Examples of character special files:
|
|
-d file
|
file exists and is a directory
|
|
-e file
|
file exists
|
|
-f file
|
file exists and is a regular file
|
|
-g file
|
file exists and is set-group-ID
|
|
-G file
|
file exists and is owned by the effective group ID
|
|
-h file
|
file exists and is a symbolic link (same as -L )
|
|
-k file
|
file exists and has its sticky bit set. When a directory or a file has the sticky bit set, its files can be deleted or renamed only by the file owner, directory owner and the root user.
|
|
-L file
|
file exists and is a symbolic link (same as -h )
|
|
-O file
|
file exists and is owned by the effective user ID
|
|
-p file
|
file exists and is a named pipe
|
|
-r file
|
file exists and read permission is granted
|
|
-s file
|
file exists and has a size greater than zero
|
|
-S file
|
file exists and is a socket. Sockets are Linux file descriptors that serve as the communication end-points for processes running on that device.
|
|
-t fd
|
file descriptor fd is opened on a terminal. File Descriptors are positive integers that act as abstract handles for IO/resources and files. All file descriptors that a process contains are stored in the directory /proc/<PID>/fd/ . <PID> stands for the process ID.
|
|
-u file
|
file exists and its set-user-ID bit is set
|
|
-w file
|
file exists and write permission is granted
|
|
-x file
|
file exists and execute (or search) permission is granted
|
|