Bash Scripting

Bash

Bash variables, redirections, history substitution, metacharacters, startup files, etc.

Shell Scripting

Shell scripting and logical constructs

Subsections of Bash Scripting

Bash

Shell and Environment Variables

Current shell

  • Where a program is executed.

Sub-shell (child shell)

  • created within a shell to run a program.

  • two types of variables: local (or shell) and environment. local variable

    • Private to the shell in which it is created.
    • Only used by programs that are started in that shell. environment variable
    • Inherited from the current shell to the sub-shell during the execution of a program
    • Value stored in an environment variable is accessible to the program, as well as any sub-programs that it spawns during its lifecycle.
    • Any environment variable set in a sub-shell is lost when the sub-shell terminates.
    • env or the printenv command to view predefined environment variables.
    • Common predefined environment variables:
      • DISPLAY
        • Stores the hostname or IP address for graphical terminal sessions
      • HISTFILE
        • Defines the file for storing the history of executed commands
      • HISTSIZE
        • Defines the maximum size for the HISTFILE
      • HOME
        • Sets the home directory path LOGNAME Retains the login name
      • MAIL
        • Contains the path to the user mail directory
      • PATH
        • Directories to be searched when executing a command. Eliminates the need to specify the absolute path of a command to run it.
      • PPID
        • Holds the identifier number for the parent program
      • PS1
        • Defines the primary command prompt PS2 Defines the secondary command prompt
      • PWD
        • Stores the current directory location
      • SHELL
        • Holds the absolute path to the primary primary shell file
      • TERM
        • Holds the terminal type value
      • UID
        • Holds the logged-in user’s UID
      • USER
        • Retains the name of the logged-in user

Setting and unsetting variables

  • export, unset, and echo to define and undefine environment variables
  • Use uppercase for variables

echo command

  • Restricted to showing the value of a specific variable

env command

  • Displays the environment variables only.
[root@localhost ~]# env
SHELL=/bin/bash
HISTCONTROL=ignoredups
HISTSIZE=1000
HOSTNAME=localhost
PWD=/root
LOGNAME=root
XDG_SESSION_TYPE=tty
MOTD_SHOWN=pam
HOME=/root
LANG=en_US.UTF-8
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=01;37;41: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=01;36:*.au=01;36:*.flac=01;36:*.m4a=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.oga=01;36:*.opus=01;36:*.spx=01;36:*.xspf=01;36:
SSH_CONNECTION=192.168.0.233 56990 192.168.0.169 22
XDG_SESSION_CLASS=user
SELINUX_ROLE_REQUESTED=
TERM=xterm-256color
LESSOPEN=||/usr/bin/lesspipe.sh %s
USER=root
SELINUX_USE_CURRENT_RANGE=
SHLVL=1
XDG_SESSION_ID=1
XDG_RUNTIME_DIR=/run/user/0
SSH_CLIENT=192.168.0.233 56990 22
which_declare=declare -f
PATH=/root/.local/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
SELINUX_LEVEL_REQUESTED=
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/0/bus
MAIL=/var/spool/mail/root
SSH_TTY=/dev/pts/0
BASH_FUNC_which%%=() {  ( alias;
 eval ${which_declare} ) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot $@
}
_=/usr/bin/env
OLDPWD=/dev/vg200

printenv command

  • Displays the environment variables only.

set command

  • View both local and environment variables.

Command and Variable substitutions

  • PS1 Environment variable sets what the prompt looks like.
  • Default value is \u@\h \W\$
    • \u
      • logged-in user name
    • \h
      • System hostname
    • \W
      • Working directory
    • \$
      • End of command prompt
  • Command whose output you want assigned to a variable must be encapsulated within either backticks hostname or parentheses $(hostname).

Input, Output, and Error Redirections

  • Input, output, and error character streams:
    • standard input (or stdin)
      • Input redirection
      • <
    • standard output (or stdout)
        • Append instead of overwrite
      • &>
        • Redirect standard error and output
    • standard error (or stderr)
      • 2>
  • File descriptors:
    • 0, 1, and 2
      • 1
        • Represents standard output location
    • Can use these to represent character streams instead of <, and >
  • noclobber feature
    • prevent overwriting of the output file
    • set -o noclobber
      • activates the feature
    • set +o noclobber
      • deactivate the feature
[root@localhost ~]# vim test.txt
[root@localhost ~]# set -o noclobber
[root@localhost ~]# echo "Hello" > test.txt
-bash: test.txt: cannot overwrite existing file
[root@localhost ~]# set +o noclobber
[root@localhost ~]# echo "Hello" > test.txt
[root@localhost ~]# cat test.txt
Hello

History Substitution

  • Command history or history expansion.
  • Can disable and re-enable if required.
  • Values may be altered for individual users by editing .bashrc or .bash_profile in the user’s home directory.
  • Three variables
    • HISTFILE
      • Defines the name and location of the history file to be used to store command history,
      • Default is .bash_history in the user’s home directory.
    • HISTSIZE
      • Size of the history buffer for the current shell.
    • HISTFILESIZE
      • Sets the maximum number of commands allowed for storage in the history file at the beginning of the current session and are written to the HISTFILE from memory at the end of the current terminal session.
      • Usually, HISTSIZE and HISTFILESIZE are set to a common value.

history command

  • Displays or reruns previously executed commands.
  • Gets the history data from the system memory as well as from the .bash_history file.
  • Shows all entries by default.
  • set +o history
    • disable history expansion
  • set -o history
    • re-enable history expansion
[root@localhost ~]# set +o history

[root@localhost ~]# history | tail 
  126  ls
  127  vim test.txt
  128  set -o noclobber
  129  echo "Hello" > test.txt
  130  set +o noclobber
  131  echo "Hello" > test.txt
  132  cat test.txt
  133  history | tail 
  134  set +0 history
  135  set +o history
  
[root@localhost ~]# vim test2.txt

[root@localhost ~]# history | tail 
  126  ls
  127  vim test.txt
  128  set -o noclobber
  129  echo "Hello" > test.txt
  130  set +o noclobber
  131  echo "Hello" > test.txt
  132  cat test.txt
  133  history | tail 
  134  set +0 history
  135  set +o history
  
[root@localhost ~]# set -o history

[root@localhost ~]# vim test2.txt

[root@localhost ~]# history | tail 
  128  set -o noclobber
  129  echo "Hello" > test.txt
  130  set +o noclobber
  131  echo "Hello" > test.txt
  132  cat test.txt
  133  history | tail 
  134  set +0 history
  135  set +o history
  136  vim test2.txt
  137  history | tail 

Add timestamps to history output system wide: echo "export HISTTIMEFORMAT='%F %T '" >> /etc/profile && source /etc/profile

Editing at the Command line

Common key combinations:

  • Ctrl+a / Home
    • Moves the cursor to the beginning of the command line
  • Ctrl+e / End
    • Moves the cursor to the end of the command line
  • Ctrl+u
    • Erase everything at and before cursor
  • Ctrl+k
    • Erase Everything at cursor and after
  • Alt+f
    • Moves the cursor to the right one word at a time
  • Alt+b
    • Moves the cursor to the left one word at a time
  • Ctrl+f / Right arrow
    • Moves the cursor to the right one character at a time
  • Ctrl+b / Left arrow
    • Moves the cursor to the left one character at a time

Tab completion

  • Hitting the Tab key twice automatically completes the entire name.
  • In case of multiple possibilities matching the entered characters, it completes up to the point they have in common and prints the rest of the possibilities on the screen.

Tilde Substitution (tilde expansion)

  • Performed on words that begin with the tilde character (~). ~
    • refers to user’s home directory.

~+ - refers to current directory

~- - Refers to previous working directory.

~USER - Refers to specific user’s home directory.

Alias Substitution (command aliasing or alias)

  • Define shortcuts for commands.
  • Bash shell includes several predefined aliases that are set during user login.
  • Shell gives precedent to an alias if an alias matches a command or program.
    • can still run the command without using the alias but preceding command with a backslash. \

alias command

  • Set an alias.
  • Internal shell command.
[root@localhost ~]# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias xzegrep='xzegrep --color=auto'
alias xzfgrep='xzfgrep --color=auto'
alias xzgrep='xzgrep --color=auto'
alias zegrep='zegrep --color=auto'
alias zfgrep='zfgrep --color=auto'
alias zgrep='zgrep --color=auto'
[root@localhost ~]# alias frog='pwd'
[root@localhost ~]# frog
/root

unalias command

  • Unset an alias.
  • Internal shell command.
[root@localhost ~]# unalias frog
[root@localhost ~]# frog
-bash: frog: command not found

Metacharacters and Wildcard

  • Metacharacters
    • Special characters that possess special meaning to the shell.
    • Used in pattern matching (a.k.a. filename expansion or file globbing) and regular expressions. dollar sign ($)
  • mark the end of a line
  • Used in regular expressions

caret (^)

  • mark the beginning of a line
  • Used in regular expressions

period (.)

  • Match a single position
  • Used in regular expressions

asterisk (*)

  • used in pattern matching
  • wildcard character
  • Matches zero to an unlimited number of characters except for the leading period (.) in a hidden filename.
  • Used in regular expressions

question mark (?)

  • Used in pattern matching
  • Wildcard character
  • Matches exactly one character except for the leading period in a hidden filename.
  • Used in regular expressions

pipe (|)

  • Send the output of one command as input to the next.
  • Also used to define alternations in regular expressions.
  • Can use as many times in a command as you need. (pipeline) - Can be used as an OR operator (alternation)
    • this|that|other

angle brackets (< >)

  • Redirections

curly brackets ({})

  • Used in regular expressions
  • Match an element a specific number of times

square brackets ([])

  • Used in pattern matching
  • Wildcard character
  • Match either a set of characters or a range of characters for a single character position.
  • Order in which they are listed has no importance.
  • Range of characters must be specified in a proper sequence such as [a-z] or [0-9].
  • Used in regular expressions

parentheses (())

  • Create a sub shell

plus (+)

  • Match a character one or more time

exclamation mark (!)

  • inverse matches

semicolon (;)

  • Run a second command after the ;

Quoting Mechanisms

  • Disable special meaning of metacharacters

Backslash (\)

  • Escape character
  • Cancel out a special character’s meaning.

single quotation (‘’)

  • Mask the meaning of all encapsulated special characters.

double quotation (“”)

  • Mask the meaning of all but the backslash (), dollar sign ($), and single quotes (‘’).

Regular expressions (regexp or regex)

  • Text pattern or an expression that is matched against a string of characters in a file or supplied input in a search operation.
  • Pattern may include a single character, multiple random characters, a range of characters, word, phrase, or an entire sentence.
  • Any pattern containing one or more white spaces must be surrounded by quotation marks.

grep command

  • Searches the contents of one or more text files or input supplied for a match.

Flags -i

  • case insensitive search

-n

  • number the lines

-v

  • exclude these lines

-w

  • find an exact match for a word

-E

  • match one or the other

-e

  • -Use patterns for matching

Jobs

  • job
    • Process that is started in the background and controlled by the terminal where it is spawned.
    • Assigned a PID (process identifier) by the kernel and, additionally, a job ID by the shell.
    • Does not hold the terminal window where it is initiated.
    • Can run multiple job simultaneously.
    • Can be brought to foreground, returned to the background, suspended, or stopped.
  • job control
    • management of multiple jobs within a shell environment

commands and control sequences for administering the jobs.

  • jobs
    • Shell built-in command
    • display jobs.
  • bg
    • Shell built-in command
    • Move a job to the background or restart a job in the background that was suspended with Ctrl+z.
  • fg
    • Shell built-in command
    • Move a job to the foreground
  • Ctrl+z
    • Suspends a foreground job and allows the terminal window to be used for other purposes

jobs command

output plus sign (+) - indicates the current background job minus sign (-) - signifies the previous job. Stopped - currently suspended - can be signaled to continue their execution with bg or fg

Shell Startup Files

  • Sourced by the shell following user authentication at the time of logging in and before the command prompt appears.
  • Aliases, functions, and scripts can be added to these files as well.
  • two types of startup files:
    • system-wide
      • Set the general environment for all users at the time of their login to the system.
      • Located in the /etc directory
      • Maintained by the Linux admin.
      • System-wide startup files for bash shell users:
        • /etc/bashrc
          • Defines functions and aliases, sets umask for user accounts with a non-login shell, establishes the command prompt, etc.
          • May include settings from the shell scripts located in the /etc/profile.d directory.
        • /etc/profile
          • Sets common environment variables such as PATH, USER, LOGNAME, MAIL, HOSTNAME, HISTSIZE, and HISTCONTROL for all users, establishes umask for user accounts with a login shell, processes the shell scripts located in the /etc/profile.d directory, and so on.
        • /etc/profile.d
          • Contains scripts for bash shell users that are executed by the /etc/profile file.
          • Files can be edited and updated.
    • per-user
      • Override or modify system default definitions set by the system-wide startup files.
      • By default, two files, in addition to the .bash_logout file, are located in the skeleton directory /etc/skel and are copied into user home directories at the time of user creation.
      • .bashrc
        • Defines functions and aliases. This file sources global definitions from the /etc/bashrc file.
      • .bash_profile
        • Sets environment variables and sources the .bashrc file to set functions and aliases.
      • .gnome2/
        • Directory that holds environment settings when GNOME desktop is started. Only available if GNOME is installed.
      • .bash_logout
        • Executed when the user leaves the shell or logs off.
        • May be customized
  • Startup file order:
    • /etc/profile > .bash_profile > .bashrc > /etc/bashrc
  • Per user settings must be added to the appropriate file for persistence.

Bash Labs

Lab: View environment variables

env
printenv

Lab: Viewing Environment variable values

  1. View the value for the PATH variable
echo $PATH
  1. View the value for the HOME variable
echo $HOME
  1. View the value for the SHELL variable
echo $SHELL
  1. View the value for the TERM variable
echo $TERM
  1. View the value for the PPID variable
echo $PPID
  1. View the value for the PS1 variable
echo $PS1
  1. View the value for the USER variable
echo $USER

Lab: Setting and Unsetting Variables

  1. Define a local variable called VR1:
VR1=RHEL9
  1. View the value of VR1:
echo $VR1
  1. Type bash at the command prompt to enter a sub-shell and then run echo $VR1 to check whether the variable is visible in the sub-shell.
echo $VR1
  1. Exit out of the subshell:
exit
  1. Turn VR1 into an environment variable:
export VR1
  1. Type bash at the command prompt to enter a sub-shell and then run echo $VR1 to check whether the variable is visible in the sub-shell.
echo $VR1
  1. Undefine this variable and erase it from the shell environment:
unset VR1
  1. Define a local variable that contains a value with one or more white spaces:
VR2="I love RHEL 9"
  1. Define and make the variable an environment variable at the same time:
export VR3="I love RHEL 9"
  1. View local and environment variables:
set

Lab: Modify Primary Command Prompt

  1. Change the value of the variable PS1 to reflect the desired information:
export PS1="< $LOGNAME on $HOSTNAME in \$PWD > " 
  1. Edit the .bash_profile file for user1 and define the value exactly as it was run in Step 1.
vim .bash_profile
  1. Test by logging off as user1 and logging back in. The new command prompt will be displayed.

Lab: Redirecting Standard Input

  1. Have the cat command read the /etc/redhat-release file and display its content on the standard output (terminal screen):
cat < /etc/redhat-release

Lab: Redirecting Standard Output

  1. Direct the ls command output to a file called ls.out:
ls > ls.out
  1. Do the same thing but using file descriptors:
ls 1> ls.out
  1. Activate the noclobber feature then try the redirect feature again:
set -o noclobber
ls > ls.out
  1. Deactivate noclobber
set +o noclobber
  1. Direct the ls command to append the output to the ls.out file instead of overwriting it:
ls >> ls.out
or
ls 1>> ls.out

Lab: Redirecting Standard Error

  1. Direct the find command issued as a normal user to search for all occurrences of files by the name core in the entire directory tree and sends any error messages produced to /dev/null
find / -name core -print 2> /dev/null
  1. Redirect both standard output and error:
ls /usr /cdr &> outerr.out
or
ls /usr /cdr 1> outerr.out 2>&1
\# means to redirect file descriptor 1 to file outerr.out as well as to file descriptor 2.
  1. Same as above but append to file:
ls /usr/cdr &>> outerr.out

Lab: Show History Variables

  1. View HISTFILE Variable:
echo $HISTFILE
  1. View HISTSIZE variable:
echo $HISTSIZE
  1. View HISTFILESIZE variable:
echo $HISTFILESIZE

Lab: History command

  1. Rune history without any options:
history
  1. Display 10 entries:
history 10
  1. Run the 15th command in history:
!15
  1. re-execute the most recent occurrence of a command that started with a particular letter or series of letters (ch for example):
!ch
  1. Issue the most recent command that contained “grep”:
!?grep?
  1. Remove entry 24 from history:
history -d 24
  1. Repeat the last command executed:
!!

Lab: Tilde expansion

  1. Display user’s home directory:
echo ~
  1. Display the current directory:
echo ~+
  1. Display the previous working directory:
echo ~-
  1. Display user1’s home directory:
echo ~user1
  1. cd into the home directory of user1 and confirm:
cd ~user1
pwd
  1. cd into a subdirectory:
cd ~/Documents/
  1. View directory information of the root user’s desktop:
ls -ld ~root/Desktop

Lab: Command Aliasing

  1. shows all aliases that are currently set for user1:
su - user1
alias
  1. Run alias as root:
alias
  1. Create an alias “search” to abbreviate the find command with several switches and arguments. Enclose the entire command within single quotation marks (‘’) to ensure white spaces are taken care of. Do not leave any spaces before and after the equal sign (=).
alias search='find / -name core -exec ls -l {} \;'
  1. Search with the new alias:
search
  1. Create and alias by the same name as rm command but adding the -i flag:
alias rm='rm -i'
  1. Run rm without using the alias:
rm file1
  1. Remove the two aliases we just created:
unalias search rm

Lab: Wildcards and Metacharacters

  1. List all files in the /etc directory that begin with letters “ma” and followed by any characters:
ls /etc/ma*
  1. List all hidden files and directories in /home/user1:
ls -d .*
  1. List all files in the /var/log directory that end in “.log”:
ls /var/log/*.log
  1. List all files and directories under /var/log with exactly four characters in their names:
ls -d /var/log/????
  1. Include all files and directories that begin with either of the two characters and followed by any number of characters.
ls /usr/bin/[yw]*
  1. Match all directory names that begin with any letter between “m” and “o” in the /etc/systemd/system directory:
ls -d /etc/systemd/system/[m-o]*
  1. Inverse results of the previous:
ls -d /etc/systemd/system/[!m-o]*

Lab: Piping

  1. Pipe the output to the less command in order to view the directory listing one screenful at a time:
ls -l /etc | less
  1. Run the last command and pipe the output to nl to number each line:
last | nl
  1. Send the output of ls to grep for the lines that do not contain the pattern “root”. Piped again for a case-insensitive selection of all lines that exclude the pattern “dec”. Number the output, and show the last four lines on the display:
ls -l /proc | grep -v root | grep -iv dec | nl | tail -4

Lab: Quoting Mechanisms

  1. Remove a file called * without deleting everything in the directory:
rm \*
  1. Display $LOGNAME without expanding the LOGNAME variable:
echo '$LOGNAME'
  1. Run the following with double quotes and without:
echo "$SHELL"
echo "\$PWD"
echo "'\'"

Lab: grep and regex

  1. Search for the pattern “operator” in the /etc/passwd file:
grep operator /etc/passwd
  1. Search for the space-separated pattern “aliases and functions” in the $HOME/.bashrc file:
grep 'aliases and functions' .bashrc
  1. Search for the pattern “nologin” in the passwd file and exclude (-v) the lines in the output that contain this pattern. Add the -n switch to show the line numbers associated with the matched lines.
grep -nv nologin /etc/passwd
  1. Find any duplicate entries for the root user in the passwd file. Prepend the caret sign (^) to the pattern “root” to mark the beginning of a line.
grep ^root /etc/passwd
  1. Identify all users in the passwd file with bash as their primary shell.
grep bash$ /etc/passwd
  1. Show the entire login.defs file but exclude all the empty lines:
grep -v ^$ /etc/login.defs
  1. Perform a case-insensitive search (-i) for all the lines in the /etc/bashrc file that match the pattern “path.”
grep -i path /etc/bashrc
  1. Print all the lines from the /etc/lvm/lvm.conf file that contain an exact match for a word (-w) “acce” followed by exactly two characters:
grep -w acce.. /etc/lvm/lvm.conf
  1. Print all the lines from the ls command output that include either (-E) the pattern “cron” or “ly”.
ls -l /etc | grep -E 'cron|ly'
  1. Show all the lines from the /etc/ssh/sshd_config file but exclude (-v) the empty lines and commented lines. Use the -e flag multiple times instead of | for either or.
sudo grep -ve ^$ -ve ^# /etc/ssh/sshd_config
  1. Learn more about regex:
man 7 regex
  1. Consult the grep man pages:
man grep

Lab: Managing jobs

  1. Issue the jobs command with the -l switch to view all the jobs running in the background:
jobs -l
  1. bring job ID 1 to the foreground and start running it:
fg %1
  1. Suspend job 1 with ctrl+z and then let it run in the background:
bg %1
  1. Terminate job ID 1, supply its PID (31726) to the kill command:
kill 31726

Lab: Shell Startup Files

  1. View the first 10 lines of /etc/bashrc:
head /etc/bashrc
  1. View the first 10 lines of /etc/profile:
head /etc/profile
  1. View the directory /etc/profile.d
ls -l /etc/profile.d/
  1. View .bashrc
cat ~/.bashrc
  1. View .bash_profile
cat ~/.bash_profile

Lab: Customize the Command Prompt (user1)

  1. Permanently customize the primary shell prompt to display “<user1@server1 in /etc >:” when this user switches into the /etc directory. The prompt should always reflect the current directory directory path.
vim ~/.bash_profile
export PS1='$USERNAME $PWD'

Lab 7-2: Redirect the Standard Input, Output, and Error (user1)

  1. Run the ls command on /etc, /dvd, and /var. Have the output printed on the screen and the errors forwarded to file /tmp/ioerror.
ls /etc /dvd /var 2> /tmp/ioerror
  1. Check the file after the command execution and analyze the results:
cat /tmp/ioerror

Shell Scripting

Shell Scripts

  • A group of Linux commands along with control structures and optional comments stored in a text file.

  • Can be executed directly at the Linux command prompt.

  • Do not need to be compiled as they are interpreted by the shell line by line.

  • Managing packages and users, administering partitions and file systems, monitoring file system utilization, trimming log files, archiving and compressing files, finding and removing unnecessary files, starting and stopping database services and applications, and producing reports.

  • Run by the shell one at a time in the order in which they are listed.

  • Each line is executed as if it is typed and run at the command prompt.

  • Control structures are utilized for creating and managing conditional and looping constructs.

  • Comments are also generally included to add information about the script such as the author name, creation date, previous modification dates, purpose, and usage.

  • If the script encounters an error during execution, the error message is printed on the screen.

  • Can use the nl command to enumerate the lines for troubleshooting.

  • Can store your scripts in the /usr/local/bin directory, which is included in the PATH of all users by default.

Script01: Displaying System Information

  • Create the first script called sys_info.sh in /usr/local/bin/
  • Use the vim editor with sudo to write the script.
#!/bin/bash
echo "Display Basic System Information"
echo "=================================="
echo
echo "The hostname, hardware, and OS information is:"
/usr/bin/hostnamectl
echo
echo "The Following users are currently logged in:"
/usr/bin/who
  • Within vim, press the ESC key and then type :set nu to view line numbers associated with each line entry.
  • Must add execute bit to run the script

Executing a Script

chmod +x /usr/local/bin/sys_info.sh

ll /usr/local/bin/sys_info.sh
-rwxr-xr-x. 1 root root 244 Jul 30 09:47 /usr/local/bin/sys_info.sh>)
  • Any user on the system can now run this script using either its name or the full path.

Let’s run the script and see what the output will look like:

$ sys_info.sh
Display Basic System Information
==================================

The hostname, hardware, and OS information is:
 Static hostname: server30
       Icon name: computer-vm
         Chassis: vm 🖴
      Machine ID: eaa6174e108d4a27bd619754…
         Boot ID: 13d8b3c167b24757b3678e4f…
  Virtualization: oracle
Operating System: Red Hat Enterprise Linux…
     CPE OS Name: cpe:/o:redhat:enterprise…
          Kernel: Linux 5.14.0-362.24.1.el…
    Architecture: x86-64
 Hardware Vendor: innotek GmbH
  Hardware Model: VirtualBox
Firmware Version: VirtualBox

The Following users are currently logged in:
root     pts/0        2024-07-30 07:22 (172.16.7.95)

Debugging a Script

Can either append the -x option to the “#!/bin/bash” at the beginning of the script to look like “#!/bin/bash -x”, or execute the script as follows:

[root@server30 ~]# bash -x sys_info.sh
+ echo 'Display Basic System Information'
Display Basic System Information
+ echo ==================================
==================================
+ echo

+ echo 'The hostname, hardware, and OS information is:'
The hostname, hardware, and OS information is:
+ /usr/bin/hostnamectl
 Static hostname: server30
       Icon name: computer-vm
         Chassis: vm 🖴
      Machine ID: eaa6174e108d4a27bd6197548ce77270
         Boot ID: 13d8b3c167b24757b3678e4fd3fe19ee
  Virtualization: oracle
Operating System: Red Hat Enterprise Linux 9.3 (Plow)     
     CPE OS Name: cpe:/o:redhat:enterprise_linux:9::baseos
          Kernel: Linux 5.14.0-362.24.1.el9_3.x86_64
    Architecture: x86-64
 Hardware Vendor: innotek GmbH
  Hardware Model: VirtualBox
Firmware Version: VirtualBox
+ echo

+ echo 'The Following users are currently logged in:'
The Following users are currently logged in:
+ /usr/bin/who
root     pts/0        2024-07-30 07:22 (172.16.7.95)
  • Actual lines from the script prefixed by the + sign and followed by the command execution result.
  • Shows the line number of the problem line in the output if there is any.
  • This way you can identify any issues pertaining to the path, command name, use of special characters, etc., and address it quickly.

Change one of the echo commands in the script to “iecho” and re-run the script in the debug mode to see the error:

[root@server30 ~]# bash -x sys_info.sh
+ echo 'Display Basic System Information'
Display Basic System Information
+ echo ==================================
==================================
+ iecho
/usr/local/bin/sys_info.sh: line 4: iecho: command not found
+ echo 'The hostname, hardware, and OS information is:'
The hostname, hardware, and OS information is:
+ /usr/bin/hostnamectl
 Static hostname: server30
       Icon name: computer-vm
         Chassis: vm 🖴
      Machine ID: eaa6174e108d4a27bd6197548ce77270
         Boot ID: 13d8b3c167b24757b3678e4fd3fe19ee
  Virtualization: oracle
Operating System: Red Hat Enterprise Linux 9.3 (Plow)     
     CPE OS Name: cpe:/o:redhat:enterprise_linux:9::baseos
          Kernel: Linux 5.14.0-362.24.1.el9_3.x86_64
    Architecture: x86-64
 Hardware Vendor: innotek GmbH
  Hardware Model: VirtualBox
Firmware Version: VirtualBox
+ echo

+ echo 'The Following users are currently logged in:'
The Following users are currently logged in:
+ /usr/bin/who
root     pts/0        2024-07-30 07:22 (172.16.7.95)

Script02: Using Local Variables

  • Create a script called use_var.sh
  • Define a local variable and display its value on the screen.
  • Re-check the value of the variable after the script execution has completed.
[root@server30 ~]# vim /usr/local/bin/use_var.sh

#!/bin/bash

echo "Setting a Local Variable"
echo "========================"
SYSNAME=server30.example.com
echo "The hostname of this system is $SYSNAME"
[root@server30 ~]# chmod +x /usr/local/bin/use_var.sh

[root@server30 ~]# use_var.sh
Setting a Local Variable
========================
The hostname of this system is server30.example.com

If you run the echo command to see what is stored in the SYSNAME variable, you will get nothing:

[root@server30 ~]# echo $SYSNAME

Script03: Using Pre-Defined Environment Variables

The following script called pre_env.sh will display the values of SHELL and LOGNAME environment variables:

[root@server30 ~]# vim /usr/local/bin/pre_env.sh

#!/bin/bash
echo "The location of my shell command is:"
echo $SHELL
echo "I am logged in as $LOGNAME"
[root@server30 ~]# chmod +x /usr/local/bin/pre_env.sh

[root@server30 ~]# pre_env.sh
The location of my shell command is:
/bin/bash
I am logged in as root

Script04: Using Command Substitution

  • Can use the command substitution feature of the bash shell and store the output generated by the command into a variable.

  • Two different ways to use command substitution: Backtics or subshell

#!/bin/bash
SYSNAME=$(hostname)
KERNVER=`uname -r`
echo "The hostname is $SYSNAME"
echo "The kernel version is $KERNVER"
[root@server30 ~]# vim /usr/local/bin/cmd_out.sh

[root@server30 ~]# chmod +x /usr/local/bin/cmd_out.sh

[root@server30 ~]# cmd_out.sh
The hostname is server30
The kernel version is 5.14.0-362.24.1.el9_3.x86_64

Shell Parameters

  • An entity that holds a value such as a name, special character, or number.
  • The parameter that holds a name is referred to as a variable
  • A parameter that holds a special character is referred to as a special parameter
    • Represents the command or script itself ($0), count of supplied arguments ($* or $@), all arguments ($#), and PID of the process ($$)
  • One or more digits, except for 0 is referred to as a positional parameter (a command line argument).
    • ($1, $2, $3 . . .) is an argument supplied to a script at the time of its invocation
    • Position is determined by the shell based on its location with respect to the calling script.
    • Positional parameters beyond 9 are to be enclosed in curly brackets.

  • Just like the variable and command substitutions, the shell uses the dollar ($) sign for special and positional parameter expansions as well.

Script05: Using Special and Positional Parameters

Create com_line_arg.sh to show the supplied arguments, total count, value of the first argument, and PID of the script:

[root@server30 ~]# vim /usr/local/bin/com_line_arg.sh

#!/bin/bash
echo "There are $# arguments specified at the command line"
echo "The arguments supplied are: $*"
echo "The first argument is: $1"
echo "The Process ID of the script is: $$"                                          
[root@server30 ~]# chmod +x /usr/local/bin/com_line_arg.sh

[root@server30 ~]# com_line_arg.sh
There are 0 arguments specified at the command line
The arguments supplied are: 
The first argument is: 
The Process ID of the script is: 1935

[root@server30 ~]# com_line_arg.sh the dog jumped over the frog
There are 6 arguments specified at the command line
The arguments supplied are: the dog jumped over the frog
The first argument is: the
The Process ID of the script is: 1936

Script06: Shifting Command Line Arguments

shift command

  • Used to move arguments one position to the left.
  • During this move, the value of the first argument is lost.
[root@server30 ~]# vim /usr/local/bin/com_line_arg_shift.sh

#!/bin/bash
echo "There are $# arguments specified at the command line"
echo "The arguments supplied are: $*"
echo "The first argument is: $1"
echo "The Process ID of the script is: $$"
shift
echo "The new first argument after the first shift is: $1"
shift
echo "The new first argument after the second shift is: $1"
[root@server30 ~]# chmod +x /usr/local/bin/com_line_arg_shift.sh

[root@server30 ~]# com_line_arg_shift.sh
There are 0 arguments specified at the command line
The arguments supplied are: 
The first argument is: 
The Process ID of the script is: 1941
The new first argument after the first shift is: 
The new first argument after the second shift is: 

[root@server30 ~]# com_line_arg_shift.sh the dog jumped over the frog
There are 6 arguments specified at the command line
The arguments supplied are: the dog jumped over the frog
The first argument is: the
The Process ID of the script is: 1942
The new first argument after the first shift is: dog
The new first argument after the second shift is: jumped
  • Multiple shifts in a single attempt may be performed by furnishing a count of desired shifts to the shift command as an argument. For example, “shift 2” will carry out two shifts, “shift 3” will make three shifts, and so on.

Logical Constructs

  • Use test conditions, which decides what to do next based on the true or false status of the condition.

The shell offers two logical constructs: if-then-fi case

Exit Codes (exit values)

  • Refer to the value returned by a command when it finishes execution.
    • Value is based on the outcome of the command.
  • If the command runs successfully, you typically get a zero exit code(return code), otherwise you get a non-zero value.
  • Return code is stored in a special shell parameter called ? (question mark).

Let’s look at the following two examples to understand their usage:

[root@server30 ~]# pwd
/root
[root@server30 ~]# echo $?
0
[root@server30 ~]# man
What manual page do you want?
For example, try 'man man'.
[root@server30 ~]# echo $?
1
  • Exit code was returned and stored in the ?.
  • Non-zero exit code was stored in ? with an error.
  • Can define exit codes within a script at different locations to help debug the script by knowing where exactly it terminated.

Test Conditions

  • Used in logical constructs to decide what to do next.
  • Can be set on integer values, string values, or files using the test command or by enclosing them within the square brackets [].
man test

Operation on Integer Value

integer1 -eq (-ne) integer2

  • Integer1 is equal (not equal) to integer2

integer1 -lt (-gt) integer2

  • Integer1 is less (greater) than integer2

integer1 -le (-ge) integer2

  • Integer1 is less (greater) than or equal to integer2

Operation on String Value

string1=(!=)string2

  • Tests whether the two strings are identical (not identical)

-l string or -z string

  • Tests whether the string length is zero

string or -n string

  • Tests whether the string length is non-zero

Operation on File

-b (-c) file

  • Tests whether the file is a block (character) device file

-d (-f) file

  • Tests whether the file is a directory (normal file)

-e (-s) file

  • Tests whether the file exists (non-empty)

-L file

  • Tests whether the file is a symlink

-r (-w) (-x) file

  • Tests whether the file is readable (writable) (executable)

-u (-g) (-k) file

  • Tests whether the file has the setuid (setgid) (sticky) bit

file1 -nt (-ot) file2

  • Tests whether file1 is newer (older) than file2

Logical Operators

!

  • The logical NOT operator

-a or && (two ampersand characters)

  • The logical AND operator. Both operands must be true for the condition to be true. Syntax: [ -b file1 && -r file1 ]

-o or || (two pipe characters)

  • The logical OR operator. Either of the two or both operands must be true for the condition to be true. Syntax: [ (x == 1 -o y == 2) ]

if-then-fi Construct

  • Evaluates the condition for true or false.
  • Executes the specified action if the condition is true.
  • Otherwise, it exits the construct.
  • Begins with an if and ends with a fi
  • Can execute an action only if the specified condition is true. It quits the statement if the condition is untrue.

The general syntax of this statement is as follows:

if condition > then > action > fi

Script07: The if-then-fi Construct

Create if_then_fi.sh to determine the number of arguments and print an error message if there are none provided:

[root@server30 ~]# vim /usr/local/bin/if_then_fi.sh

#!/bin/bash 
if [ $# -ne 2 ] # Ensure there is a space after [ and before ] 
then 
        echo "Error: Invalid number of arguments supplied" 
        echo "Usage: $0 source_file destination_file" 
exit 2 
fi 
echo "Script terminated"
[root@server30 ~]# chmod +x /usr/local/bin/if_then_fi.sh

[root@server30 ~]# if_then_fi.sh
Error: Invalid number of arguments supplied
Usage: /usr/local/bin/if_then_fi.sh source_file destination_file

This script will display the following messages on the screen if it is executed without exactly two arguments specified at the command line:

[root@server30 ~]# if_then_fi.sh
Error: Invalid number of arguments supplied
Usage: /usr/local/bin/if_then_fi.sh source_file destination_file

Return code value reflects the exit code in the script .

[root@server30 ~]# echo $?
2

Return code will be 0 if you supply a pair of arguments:

[root@server30 ~]# if_then_fi.sh a b
Script terminated
[root@server30 ~]# echo $?
0

if-then-else-fi Construct

  • Can execute an action if the condition is true and another action if the condition is false.

The general syntax of this statement is as follows:

if condition > then > action1 > else > action2 > fi

Script08: The if-then-else-fi Construct

Create a script called if_then_else_fi.sh that will accept an integer value as an argument and tell if the value is positive or negative:

vim /usr/local/bin/if_then_else_fi.sh
#!/bin/bash
if [ $1 -gt 0 ]
then
        echo "$1 is a positive integer value"
else
        echo "$1 is a negative integer value"
fi
[root@server30 ~]# chmod +x /usr/local/bin/if_then_else_fi.sh
[root@server30 ~]# if_then_else_fi.sh
/usr/local/bin/if_then_else_fi.sh: line 2: [: -gt: unary operator expected
 is a negative integer value
[root@server30 ~]# if_then_else_fi.sh 3
3 is a positive integer value
[root@server30 ~]# if_then_else_fi.sh -3
-3 is a negative integer value
[root@server30 ~]# if_then_else_fi.sh a
/usr/local/bin/if_then_else_fi.sh: line 2: [: a: integer expression expected
a is a negative integer value

[root@server30 ~]# echo $?
0

The if-then-elif-fi Construct

  • Can define multiple conditions and associate an action with each one of them.
  • The action corresponding to the true condition is performed.

The general syntax of this statement is as follows:

if condition1 > then action1 > elif condition2 > then action2 > elif condition3 > then action3 > else > action(n) > fi

Script09: The if-then-elif-fi Construct (Example 1)

Create if_then_elif_fi.sh script to accept an integer value as an argument and tell if the integer is positive, negative, or zero. If a non-integer value or no argument is supplied, the script will complain. Employ the exit command after each action to help you identify where it exited.

[root@server30 ~]# vim /usr/local/bin/if_then_elif_fi.sh
#!/bin/bash
if [ $1 -gt 0 ]
then
        echo "$1 is a positive integer value"
exit 1
elif [ $1 -eq 0 ]
then
        echo "$1 is a zero integer value"
exit 2
elif [ $1 -lt 0 ]
then
        echo "$1 is a negative integer value"
exit 3
else
        echo "$1 is not an integer value. Please supply an i
nteger."
exit 4
fi
[root@server30 ~]# if_then_elif_fi.sh -0
-0 is a zero integer value

[root@server30 ~]# echo $?
2

[root@server30 ~]# if_then_elif_fi.sh -1
-1 is a negative integer value

[root@server30 ~]# echo $?
3

[root@server30 ~]# if_then_elif_fi.sh 10
10 is a positive integer value

[root@server30 ~]# echo $?
1

[root@server30 ~]# if_then_elif_fi.sh abd
/usr/local/bin/if_then_elif_fi.sh: line 2: [: abd: integer expression expected
/usr/local/bin/if_then_elif_fi.sh: line 6: [: abd: integer expression expected
/usr/local/bin/if_then_elif_fi.sh: line 10: [: abd: integer expression expected
abd is not an integer value. Please supply an i
nteger.>)

[root@server30 ~]# echo $?
4

Script10: The if-then-elif-fi Construct (Example 2)

Create ex200_ex294.sh to display the name of the Red Hat exam RHCSA or RHCE in the output based on the input argument (ex200 or ex294). If a random or no argument is provided, it will print “Usage: Acceptable values are ex200 and ex294”. Add white spaces in the conditions.

[root@server30 ~]# vim /usr/local/bin/ex200_ex294.sh
#!/bin/bash
if [ "$1" = ex200 ]
then
        echo "RHCSA"
elif [ "$1" = ex294 ]
then
        echo "RHCE"
else
        echo "Usage: Acceptable values are ex200 and ex294"
fi
[root@server30 ~]# chmod +x /usr/local/bin/ex200_ex294.sh

[root@server30 ~]# ex200_ex294.sh ex200
RHCSA

[root@server30 ~]# ex200_ex294.sh ex294
RHCE

[root@server30 ~]# ex200_ex294.sh frog
Usage: Acceptable values are ex200 and ex294

Looping Constructs

  • Perform certain task on a number of given elements.
  • Or repeatedly until a specified condition becomes true or false.
  • Examples:
    • if plenty of disks need to be initialized for use in LVM, you can either run the pvcreate command on each disk one at a time manually or employ a loop to do it for you.
    • Based on a condition, you may want a program to continue to run until that condition becomes true or false.

Three looping constructs: for-do-done

  • for loop is also referred to as the foreach loop.
  • iterates on a list of given values until the list is exhausted. while-do-done
  • while loop runs repeatedly until the specified condition becomes false. until-do-done
  • until loop does just the opposite of the while loop
  • Performs an operation repeatedly until the specified condition becomes true.

Test Conditions

let command

  • Used in looping constructs to evaluate a condition at each iteration.
  • Compares the value stored in a variable against a pre-defined value
  • Each time the loop does an iteration, the variable value is altered.
  • Can enclose the condition for arithmetic evaluation within a pair of parentheses (( )) or quotation marks (" “) instead of using the let command explicitly.

Operators used in test conditions

!

  • Negation

+ / – / * / /

  • Addition / subtraction /multiplication / division

%

  • Remainder

< / <=

  • Less than / less than or equal to

> / >=

  • Greater than / greater than or equal to

=

  • Assignment

== / !=

  • Comparison for equality /non-equality

The for Loop

  • Executed on an array of elements until all the elements in the array are consumed.
  • Each element is assigned to a variable one after the other for processing.

The general syntax of this construct is as follows:

for VAR in list > do > action > done

Script11: Print Alphabets Using for Loop

Create script for_do_done.sh script that initializes the variable COUNT to 0. The for loop will read each letter sequentially from the range placed within curly brackets (no spaces before the letter A and after the letter Z), assign it to another variable LETTER, and display the value on the screen. The expr command is an arithmetic processor, and it is used here to increment the COUNT by 1 at each loop iteration.

[root@server10 ~]# vim /usr/local/bin/for_do_done.sh
#!/bin/bash
COUNT=0
for LETTER in {A..Z}
do
        COUNT=`/usr/bin/expr $COUNT + 1`
        echo "Letter $COUNT is [$LETTER]"
done
[root@server10 ~]# chmod +x /usr/local/bin/for_do_done.sh
[root@server10 ~]# for_do_done.sh
Letter 1 is [A]
Letter 2 is [B]
Letter 3 is [C]
Letter 4 is [D]
Letter 5 is [E]
Letter 6 is [F]
Letter 7 is [G]
Letter 8 is [H]
Letter 9 is [I]
Letter 10 is [J]
Letter 11 is [K]
Letter 12 is [L]
Letter 13 is [M]
Letter 14 is [N]
Letter 15 is [O]
Letter 16 is [P]
Letter 17 is [Q]
Letter 18 is [R]
Letter 19 is [S]
Letter 20 is [T]
Letter 21 is [U]
Letter 22 is [V]
Letter 23 is [W]
Letter 24 is [X]
Letter 25 is [Y]
Letter 26 is [Z]

Script12: Create Users Using for Loop

Create script create_user.sh script to create several Linux user accounts. As each account is created, the value of the variable ? is checked. If the value is 0, a message saying the account is created successfully will be displayed, otherwise the script will terminate. In case of a successful account creation, the passwd command will be invoked to assign the user the same password as their username.

[root@server10 ~]# vim /usr/local/bin/create_user.sh
#!/bin/bash

for USER in user{10..12}
do
        echo "Create account for user $USER"
        /usr/sbin/useradd $USER
if [ $? = 0 ]
then
        echo $USER | /usr/bin/passwd --stdin $USER
        echo "$USER is created successfully"
else
        echo "Failed to create account $USER"
exit
fi
done
[root@server10 ~]# chmod +x /usr/local/bin/create_user.sh

[root@server10 ~]# create_user.sh
Create account for user user10
Changing password for user user10.
passwd: all authentication tokens updated successfully.
user10 is created successfully
Create account for user user11
Changing password for user user11.
passwd: all authentication tokens updated successfully.
user11 is created successfully
Create account for user user12
Changing password for user user12.
passwd: all authentication tokens updated successfully.
user12 is created successfully

Script fails if ran again:

[root@server10 ~]# create_user.sh
Create account for user user10
useradd: user 'user10' already exists
Failed to create account user10

Shell Scripting DIY Labs

Lab: Write Script to Create Logical Volumes

  • Present 2x1GB virtual disks to server40 in VirtualBox Manager.
  • As user1 with sudo on server40, write a single bash script to create 2x400MB partitions on each disk using parted and then bring both partitions into LVM control with the pvcreate command.
 vim /usr/local/bin/lvscript.sh
  • Create a volume group called vgscript and add both physical volumes to it.
  • Create three logical volumes each of size 200MB and name them lvscript1, lvscript2, and lvscript3.
 #!/bin/bash
 for DEVICE in "/dev/sd"{b..c}
 do
        echo "Creating partition 1 with the size of 400MB on $DEVICE"
        parted $DEVICE mklabel msdos
        parted $DEVICE mkpart primary 1 401
        pvcreate $DEVICE[1]

        echo "Creating partition 2 with the size of 400MB on $DEVICE"
        parted $DEVICE mkpart primary 402 802
        pvcreate $DEVICE[2]
        vgcreate vgscript $DEVICE[1] $DEVICE[2]
 done
 for LV in "lvscript"{1..3}
 do
        echo "Creating logical volume $LV in volume group vgscript with the size of 200MB"
        lvcreate vgscript -L 200MB -n $LV
 done

Lab: Write Script to Create File Systems

  • Write another bash script to create xfs, ext4, and vfat file system structures in the logical volumes, respectively.
  • Create mount points /mnt/xfs, /mnt/ext4, and /mnt/vfat, and mount the file systems.
  • Include the df command with -h in the script to list the mounted file systems.
 vim /usr/local/bin/fsscript.sh
 [root@server40 ~]# chmod +x /usr/local/bin/fsscript.sh
 #!/bin/bash
 for DEVICE in lvscript{1..3}
 do
 if [ "$DEVICE" = lvscript1 ]
 then
        echo "Creating xfs filesystem on logical volume lvscript1"
        echo
        mkfs.xfs /dev/vgscript/lvscript1
        echo "Creating /mnt/xfs"
        mkdir /mnt/xfs
        echo "Mounting filesystem"
        mount /dev/vgscript/lvscript1 /mnt/xfs
 elif [ "$DEVICE" = lvscript2 ]
 then    
        echo "Creating ext4 filesystem on logical volume lvscript2"
        echo
        mkfs.ext4 /dev/vgscript/lvscript2
        echo "Creating /mnt/ext4"
        mkdir /mnt/ext4
        echo "Mounting filesystem"
        mount /dev/vgscript/lvscript2 /mnt/ext4

 elif [ "$DEVICE" = lvscript3 ]
 then    
        echo "Creating vfat filesystem on logical volume lvscript3"
        echo
        mkfs.vfat /dev/vgscript/lvscript3
        echo "Creating /mnt/vfat"
        mkdir /mnt/vfat
        echo "Mounting filesystem"
        mount /dev/vgscript/lvscript3 /mnt/vfat
        echo
        echo
        echo "Done!"
                df -h
 else
        echo

 fi
 done
 [root@server40 ~]# fsscript.sh
 Creating xfs filesystem on logical volume lvscript1

 Filesystem should be larger than 300MB.
 Log size should be at least 64MB.
 Support for filesystems like this one is deprecated and they will not be supported in future releases.
 meta-data=/dev/vgscript/lvscript1 isize=512    agcount=4,  agsize=12800 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1,  rmapbt=0
         =                       reflink=1    bigtime=1 inobtcount=1  nrext64=0
 data     =                       bsize=4096   blocks=51200, imaxpct=25
         =                       sunit=0      swidth=0 blks
 naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
 log      =internal log           bsize=4096   blocks=1368, version=2
         =                       sectsz=512   sunit=0 blks, lazy- count=1
 realtime =none                   extsz=4096   blocks=0, rtextents=0
 Creating /mnt/xfs
 Mounting filesystem
 Creating ext4 filesystem on logical volume lvscript2

 mke2fs 1.46.5 (30-Dec-2021)
 Creating filesystem with 204800 1k blocks and 51200 inodes
 Filesystem UUID: b16383bf-7b65-4a00-bb6d-c297733f60b3
 Superblock backups stored on blocks: 
	8193, 24577, 40961, 57345, 73729

 Allocating group tables: done                            
 Writing inode tables: done                            
 Creating journal (4096 blocks): done
 Writing superblocks and filesystem accounting information: done 

 Creating /mnt/ext4
 Mounting filesystem
 Creating vfat filesystem on logical volume lvscript3

 mkfs.fat 4.2 (2021-01-31)
 Creating /mnt/vfat
 Mounting filesystem


 Done!

Lab 21-3: Write Script to Configure New Network Connection Profile

  • Present a new network interface to server40 in VirtualBox Manager.
  • As user1 with sudo on server40, write a single bash script to run the nmcli command to configure custom IP assignments (choose your own settings) on the new network device.
  • Make a copy of the /etc/hosts file as part of this script.
  • Choose a hostname of your choice and add a mapping to the /etc/hosts file without overwriting existing file content.
 [root@server40 ~]# vim /usr/local/bin/network.sh
 #!/bin/bash
 cp /etc/hosts /etc/hosts.bak &&
 nmcli c a type Ethernet con-name enp0s9 ifname enp0s9 ip4  10.32.32.2/24 gw4 10.32.32.1
 echo "10.32.33.14 frog.example.com frog" >> /etc/hosts
 [root@server40 ~]# chmod +x /usr/local/bin/network.sh
 [root@server40 ~]# network.sh
 Connection 'enp0s9' (5a342243-e77b-452e-88e2-8838d3ecea6d)  successfully added.
 [root@server40 ~]# cat /etc/hosts
 127.0.0.1   localhost localhost.localdomain localhost4  localhost4.localdomain4
 ::1         localhost localhost.localdomain localhost6  localhost6.localdomain6
 10.32.33.14 frog.example.com frog
 [root@server40 ~]# ip a
 enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel  state UP group default qlen 1000
    link/ether 08:00:27:1d:f4:c1 brd ff:ff:ff:ff:ff:ff
    inet 10.32.32.2/24 brd 10.32.32.255 scope global noprefixroute enp0s9
       valid_lft forever preferred_lft forever
    inet6 fe80::2c5d:31cc:1d79:6b43/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
 [root@server40 ~]# nmcli d s
 DEVICE  TYPE      STATE                   CONNECTION 
 enp0s3  ethernet  connected               enp0s3     
 enp0s8  ethernet  connected               enp0s8     
 enp0s9  ethernet  connected               enp0s9     
 lo      loopback  connected (externally)  lo