Shell for DevOps
Linux Filesystem
In a Linux distribution, several critical directories hold essential system files, configurations, and user data. Among these, /etc
, /var
, /bin
, /usr
, and /home
are some of the most important directories.
/etc
: This directory contains system-wide configuration files. It houses crucial settings for various services, software applications, and the system itself. Files such as /etc/passwd
(user account information), /etc/apt/sources.list
(APT package manager configuration), and /etc/hostname
(system hostname) reside here. Administrators often tweak settings in this directory to manage system behavior and software configurations.
/var
: This directory stores variable data generated by running processes. It includes files that change frequently during system operation, such as logs (/var/log
), databases (/var/lib
), mail (/var/mail
), and temporary files (/var/tmp
). System logs and application data often reside here, offering insights into system health and performance.
/bin
and /usr
: These directories contain executable binaries and essential system commands. /bin
holds fundamental commands crucial for system booting and repair, while /usr/bin
contains standard user commands and binaries for installed software.
/home
: This directory houses user home directories. Each user typically has a dedicated subdirectory (/home/username
) storing their personal files, configurations, and settings. It's a critical space for user-specific data, allowing customization and privacy for individual users.
These directories form the backbone of a Linux system, encompassing critical configurations, system data, executable files, and user-specific information essential for the system's functionality and user experience.
├── bin # Essential system binaries.
│ ├── /bin # Core command binaries.
│ ├── /sbin # System binaries for administration tasks.
│ └── /usr # Additional user binaries.
│ └── /usr/bin # User command binaries.
├── boot # Boot-related files.
│ ├── /boot/grub # GRUB bootloader files and config.
│ └── /boot/kernel # Kernel and related files.
├── dev # Device files representing hardware devices.
│ ├── /dev/pts # Pseudo-terminal devices.
│ └── /dev/shm # Shared memory files and objects.
├── etc # System-wide configuration files.
│ ├── /etc/network # Network configuration files.
│ ├── /etc/apt # APT package manager configuration.
│ └── /etc/default # Default config for various applications.
├── home # User home directories.
│ ├── /home/user1 # Individual user directories.
│ └── /home/user2
├── lib # Essential shared libraries.
├── media # Mount point for removable media.
├── mnt # Temporary mount point for additional filesystems.
├── opt # Optional third-party software.
├── proc # Virtual filesystem providing process-related info.
├── root # Home directory for the root user.
├── run # System information since the last boot.
│ └── /run/user # User-specific runtime info.
├── sbin # System binaries for administration tasks.
├── srv # Site-specific data served by the system.
├── sys # Virtual filesystem with hardware device info.
├── tmp # Temporary files, deleted upon reboot.
├── usr # User-related programs and resources.
│ ├── /usr/local # Locally installed software.
│ └── /usr/share # Architecture-independent data.
└── var # Variable data, logs, caches, temporary files.
├── /var/log # System log files.
└── /var/cache # Cached data from installed packages.
You can displays the directory structure in a tree-like format.
Example:
tree
Permissions
In Linux distributions, file permissions and ownership are managed through a robust system known as "rights management." This system controls access to files and directories, ensuring security and privacy across the system. Each file and directory has associated permissions determining who can read, write, or execute them. These permissions are categorized for three types of users: the file owner, the user group associated with the file, and others.
Read file permisions
When you use ls -l
in a terminal, you'll see an output similar to this:
-rwxr-xr-- 1 user group 4096 Jan 1 12:00 example.txt
Let's break down what each part of this output signifies:
File Permissions: The
-rwxr-xr--
part represents permissions for the file.- The first character indicates file type (
-
for a regular file). - The next nine characters (
rwxr-xr--
) denote permissions for owner, group, and others.- The first three characters represent owner permissions (
rwx
). - The next three represent group permissions (
r-x
). - The last three represent permissions for others (
r--
).
- The first three characters represent owner permissions (
- The first character indicates file type (
File Owner and Group: The
user
is the file's owner, andgroup
is the group associated with the file.File Size, Date, and Name: The
4096 Jan 1 12:00 example.txt
part shows the file size, modification date, and file name.r
denotes read permission.w
denotes write permission.x
denotes execute permission.-
denotes lack of a specific permission.
For instance, in -rwxr-xr--
:
- The owner (
rwx
) has read, write, and execute permissions. - The group (
r-x
) has read and execute permissions. - Others (
r--
) have only read permission.
This visual representation from ls -l
allows you to quickly interpret file permissions and understand who has access to read, write, and execute the file.
Changing Permissions
Permissions are modified using commands like chmod
. For example, granting read and write permissions to the owner and group of a file named example.txt
:
chmod ug+rw example.txt
Ownership Management
Ownership is altered using chown
. To change the owner of example.txt
to newowner
:
chown newowner example.txt
#!/bin/bash
# Changing permissions
chmod ug+rw example.txt
# Changing ownership
chown newowner example.txt
This script demonstrates using chmod
and chown
to modify file permissions and ownership, ensuring proper management and security within a Linux environment.
Octal notation
Octal notation simplifies permission settings using three digits, each representing permission types for owner, group, and others.
For instance:
chmod 755 file.txt
sets:- Owner: Read (4) + Write (2) + Execute (1) = 7
- Group and Others: Read (4) + Execute (1) = 5
This notation streamlines permission management, facilitating precise access control in Linux.
Navigation
cd
Change directory.
cd /path/to/directory
ls
List directory contents.
user@host:/$ ls /path/to/directory
bin boot dev etc home initrd.img initrd.img.old lib lib32 lib64 libx32 lost+found media mnt opt proc root run sbin srv sys tmp usr var vmlinuz vmlinuz.old
-l
: Long format, displaying detailed information.
pwd
Print working directory.
$ cd /etc
$ pwd
/etc
which
Locates an executable file in your shell’s search path.
usaer@host:~$ which java
/usr/bin/java
Package Managers
apt
Package manager for Debian-based systems.
apt update
update
: Updates the package index.
Config Files:
/etc/apt/sources.list
: Contains a list of repository URLs used byapt
./etc/apt/sources.list.d/
: Additional sources forapt
.
Removing Packages:
apt remove package_name
: Removes a package.apt purge package_name
: Removes a package along with its configuration files.
yum
Package manager for RPM-based systems like CentOS.
yum install package_name
Config Files:
/etc/yum.conf
: Main configuration file foryum
./etc/yum.repos.d/
: Directory containing repository configuration files.
Removing Packages:
yum remove package_name
: Removes a package.
dnf
Package manager, newer version of yum
, used in Fedora.
dnf search keyword
Config Files:
/etc/dnf/dnf.conf
: Main configuration file fordnf
./etc/yum.repos.d/
: Directory containing repository configuration files.
Removing Packages:
dnf remove package_name
: Removes a package.
pacman
Package manager for Arch Linux.
pacman -Syu
-Syu
: Synchronizes package databases and upgrades installed packages.
Config Files:
/etc/pacman.conf
: Main configuration file forpacman
./etc/pacman.d/
: Directory containing repository configuration files.
Removing Packages:
pacman -R package_name
: Removes a package.
Shell Scripting
- Create a
.sh
file - add the following header inside it
#!/bin/bash
# Put your command to execute HERE
echo "HelloWorld !"
- Add the right of execution to the file
chmod +x myscript.sh
- You can now execute the script
./myscript.sh
HelloWorld !
Passing argument to a bash shell script
count_line.sh
#!/bin/bash
nlines=$(wc -l < $1)
echo "There are $nlines lines in $1"
./count_lines.sh /etc/group
There are 73 lines in /etc/group
Processes & Services
ps
Display information about running processes.
Example:
ps aux
aux
: Display all processes with a user-oriented format.
When you run the ps
command in Unix-like operating systems, it displays information about active processes. Among the various columns of information, you might see a column labeled PD
. This column represents the "Parent Process ID" or "PPID".
The Parent Process ID refers to the Process ID (PID) of the parent process that spawned the current process. In other words, it indicates which process is the parent of the process listed in the current row.
For example, if you see a pd
value of 1234
, it means that the process listed in that row was created by the process with PID 1234
.
Understanding the parent-child relationship between processes can be crucial for troubleshooting and analyzing system behavior. It helps in determining how processes are related and how they interact with each other.
Here's an example of the output of the ps
command with the pd
column:
PID PPID CMD
1001 999 bash
1002 1001 └─── ls
1003 1001 └─── ps
Process with PID 1001
(bash) is the parent process of processes with PIDs 1002
(ls) and 1003
(ps). Processes ls
and ps
were spawned by the bash
process.
top
or htop
Monitoring tools to view system processes and resource usage.
Example:
top
Shift + M
: Sort by memory usage intop
.F6
(inhtop
): Sort by various fields.
Chrono table (Cron or CronTab)
Cron is a task scheduling utility for Unix and Unix-like systems. It allows users to schedule commands or scripts to run periodically at specified intervals.
To edit the cron configuration file:
crontab -e
* * * * * command_to_execute
The general syntax for configuring a task in a cron tab is as follows, where the five asterisks (*) represent respectively: - Minute (0-59) - Hour (0-23) - Day of the month (1-31) - Month (1-12) - Day of the week (0-7, 0 and 7 represent Sunday)
You can verify that the task has been added correctly using the crontab -l
command.
SystemD
for MacOS
Use LaunchAgent or LaunchDaemon service implementation here
Systemd is a service and process management system for Linux systems. It offers advanced features such as parallel startup, dependency management, service monitoring, and more.
Configuring a service with systemd involves creating a .service
file that specifies the service's settings. Here's an example of a basic service file:
[Unit]
Description=Service Description
[Service]
Type=Service Type
ExecStart=/path/to/command_to_execute
Restart=Restart Policy
[Install]
WantedBy=default.target
[Unit]
: Section containing metadata about the service.[Service]
: Section describing the service itself.[Install]
: Section specifying how the service should be installed.
To refresh the list of systemd services:
sudo systemctl daemon-reload
To Start your service:
sudo systemctl start mon_service
To Check the status of your service:
sudo systemctl status mon_service
Console Output:
● mon_service.service - My demonstration service
Loaded: loaded (/etc/systemd/system/mon_service.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2024-02-14 10:00:00 CET; 5s ago
Main PID: 12345 (mon_script.sh)
Tasks: 1 (limit: 4915)
Memory: 10.0M
CGroup: /system.slice/mon_service.service
└─12345 /path/to/mon_script.sh
Feb 14 10:00:00 hostname systemd[1]: Started My demonstration service.
You can also configure a Timer associated with your service:
- Create a timer file named
mon_service.timer
in the directory/etc/systemd/system/
:
sudo nano /etc/systemd/system/mon_service.timer
- Add the following content to the file:
[Unit]
Description=My timer for mon_service
[Timer]
OnCalendar=*-*-* 00:00:00
Unit=mon_service.service
[Install]
WantedBy=timers.target
In this example, OnCalendar=*-*-* 00:00:00
means the timer will trigger every day at midnight.
To start your timer:
sudo systemctl daemon-reload
sudo systemctl enable mon_service.timer
sudo systemctl start mon_service.timer
To check the status of your timer:
sudo systemctl status mon_service.timer
Network Debugging
ping
Test connectivity to a remote host.
Example:
ping google.com
ssh
Securely connect to a remote server.
Example:
ssh username@hostname
telnet
Communicate with another host using the Telnet protocol (less secure).
Example:
telnet example.com 80
netstat
The netstat
command is a network utility tool used to display network connections, routing tables, interface statistics. It provides information about network connections and routing tables, which can be useful for troubleshooting network-related issues.
Display all TCP and UDP connections:
netstat -a
Display TCP connections with numerical addresses:
netstat -t -n
Display routing table:
netstat -r
Display listening TCP sockets:
netstat -l -t
wget
Retrieve content from web servers via HTTP, HTTPS, FTP.
Example:
wget https://example.com/file.tar.gz
ip
The ip
command is used for showing/manipulating routing, network devices, interfaces, and tunnels in Unix-like operating systems.
To display network interfaces and their addresses, use the following command:
ip address show
Output:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
inet 192.168.1.100/24 brd 192.168.1.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe11:2233/64 scope link
valid_lft forever preferred_lft forever
dig
The dig
command is used for querying DNS servers for various DNS records.
To query DNS records for a domain, use the following command:
dig example.com
Output:
; <<>> DiG 9.10.6 <<>> example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58283
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 604800 IN A 93.184.216.34
;; Query time: 1 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Mon Feb 07 18:23:10 PST 2024
;; MSG SIZE rcvd: 55
host
The host
command is used to perform DNS lookups. It retrieves domain name to IP address mappings by querying DNS servers.
To perform a DNS lookup for a domain name, use the following command:
host example.com
Output:
example.com has address 93.184.216.34
example.com has IPv6 address 2606:2800:220:1:248:1893:25c8:1946
Others
grep
Search for specific patterns in files.
Example:
grep "pattern" file.txt
-i
: Ignore case distinctions.-r
: Recursively search subdirectories.-n
: Show line numbers.
sed
Stream editor for modifying and formatting text.
Example:
sed 's/old_text/new_text/' file.txt
's/old_text/new_text/'
: Substituteold_text
withnew_text
.-i
: Edit files in place.
awk
Text processing tool for extracting and manipulating data.
Example:
awk '{print $1}' file.txt
'{print $1}'
: Print the first field of each line.-F
: Set field separator.
git
Version control system for tracking changes in code.
Example:
git clone repository_url
clone
: Clone a repository.add
: Add file contents with the index.commit
: create a new commit from the current indexpush
: push local commit to the remote branchpull
: retrieve commits from the remote branch
Exercises
Requirement For Windows
Linux subsystem for windows here
🧪 Exercise 1 - File System Management
Objective: Create a script that organizes files in a directory, lists permissions, and performs basic operations as follow
[drwxr-xr-x ] personnages
├── [drwxrwxr-x ] mascottes
│ ├── [-rw-r--r-- ] beastie
│ ├── [-rw-r--r-- ] bibendum
│ ├── [-rw-r--r-- ] mario
│ └── [-rw-r--r-- ] sonic
└── [drwxr-xr-x ] super heros
├── [drwxr-xr-x ] femmes
│ ├── [drwxrwxr-x ] cape
│ │ ├── [drwxrwxr-x ] batgirl
│ │ └── [drwxrwxr-x ] wonderwoman
│ └── [drwxrwxr-x ] sans cape
│ ├── [drwxrwxr-x ] electra
│ └── [drwxrwxr-x ] superwoman
└── [drwxr-xr-x ] hommes
├── [drwxrwxr-x ] cape
│ ├── [-rw-r--r-- ] batman
│ ├── [-rw-r--r-- ] superman
│ └── [-rw-r--r-- ] thor
└── [drwxrwxr-x ] sans cap
├── [-rw-r--r-- ] antman
├── [-rw-r--r-- ] daredevil
├── [-rw-r--r-- ] linuxman
└── [-rw-r--r-- ] spiderman
solution
#!/bin/bash
# Check if a root directory is specified as an argument
root_dir="${1:-.}"
# Create the directory and file structure
directories=(
"$root_dir/personnages/mascottes"
"$root_dir/personnages/super heros/femmes/cape"
"$root_dir/personnages/super heros/femmes/sans cape"
"$root_dir/personnages/super heros/hommes/cape"
"$root_dir/personnages/super heros/hommes/sans cap"
"$root_dir/personnages/super heros/femmes/cape/batgirl"
"$root_dir/personnages/super heros/femmes/cape/wonderwoman"
"$root_dir/personnages/super heros/femmes/sans cape/electra"
"$root_dir/personnages/super heros/femmes/sans cape/superwoman"
)
files=(
"$root_dir/personnages/mascottes/beastie"
"$root_dir/personnages/mascottes/bibendum"
"$root_dir/personnages/mascottes/mario"
"$root_dir/personnages/mascottes/sonic"
"$root_dir/personnages/super heros/hommes/cape/batman"
"$root_dir/personnages/super heros/hommes/cape/superman"
"$root_dir/personnages/super heros/hommes/cape/thor"
"$root_dir/personnages/super heros/hommes/sans cap/antman"
"$root_dir/personnages/super heros/hommes/sans cap/daredevil"
"$root_dir/personnages/super heros/hommes/sans cap/linuxman"
"$root_dir/personnages/super heros/hommes/sans cap/spiderman"
)
# Create directories
for dir in "${directories[@]}"; do
mkdir -m 775 -p "$dir"
done
# Create files
for file in "${files[@]}"; do
touch -m 664 "$file"
done
# Display permissions using ls
ls -lR --color=auto "$root_dir/personnages"
- It seems that "linuxman" is not a superhero. In fact, he is called "Tux" and should be located in the "mascots" directory. Using the "mv" command, move the file "linuxman" to "tux" in the mascots directory.
- Rename the directory "superheroes" to "comics".
- Using the "echo" command: write into the file "batman" the content "Bruce Wayne hides behind this character".
- Using the "echo" command: append to the file "batman" the content "he lives in Gotham".
- Using the "echo" command: write into the file "dardevil" the content "Homer Simpson hides behind this character".
- Oh no, it's not Homer. With the "echo" command, overwrite the content of the file "dardevil" with the content "Dardevil is a blind comic character".
- Using the "cat" command, in a single command, copy the contents of the "batman" and "dardevil" files into the "mascots/mixdarbat" file.
- Switch to root mode.
- Create a user named "fanboy".
- Copy the directory "characters" into /home/fanboy.
- Use the "chown" command to change the owner and group of this directory.
- Create a symbolic link "persofanboy" pointing to /home/fanboy/characters.
- Create a symbolic link "perso_yourname" pointing to /home/yourname/characters.
- Using the "ls" command, save the complete tree structure of /home/fanboy/characters into a file "14.txt".
- In the file "14.txt", you will find lines with the word "total". Using the grep command, copy the contents of the file "14.txt" into the file "15.txt" by removing occurrences of the word "total".
- Save the last 250 lines of your history in the file "myhistory" by removing any lines where you used the "cd" command. You will use the grep command again.
solution
#!/bin/bash
# 1. Move linuxman to tux in mascots directory
mv personnages/super\ heros/hommes/sans\ cap/linuxman personnages/mascottes/tux
# 2. Rename the directory superheroes to comics
mv personnages/super\ heros personnages/comics
# 3. Write into the file batman
echo "Bruce Wayne hides behind this character" > personnages/comics/hommes/cape/batman
# 4. Append to the file batman
echo "he lives in Gotham" >> personnages/comics/hommes/cape/batman
# 5. Write into the file dardevil
echo "Homer Simpson hides behind this character" > personnages/comics/hommes/sans\ cap/daredevil
# 6. Overwrite the content of the file dardevil
echo "Dardevil is a blind comic character" > personnages/comics/hommes/sans\ cap/daredevil
# 7. Copy the contents of batman and dardevil into mascots/mixdarbat
cat personnages/comics/hommes/cape/batman personnages/comics/hommes/sans\ cap/daredevil > personnages/mascottes/mixdarbat
# 8. Switch to root mode
sudo su
# 9. Create a user named "fanboy"
useradd fanboy
# 10. Copy the directory characters into /home/fanboy
cp -r personnages /home/fanboy
# 11. Change owner and group of the directory
chown -R fanboy:fanboy /home/fanboy/personnages
# 12. Create a symbolic link "persofanboy" pointing to /home/fanboy/characters
ln -s /home/fanboy/personnages /home/fanboy/persofanboy
# 13. Create a symbolic link "perso_yourname" pointing to /home/yourname/characters
# Replace "yourname" with your actual username
ln -s /home/yourname/personnages /home/yourname/perso_yourname
# 14. Save the complete tree structure of /home/fanboy/characters into 14.txt
ls -lR /home/fanboy/personnages > 14.txt
# 15. Remove occurrences of the word "total" from 14.txt and save into 15.txt
grep -v "total" 14.txt > 15.txt
# 16. Save the last 250 lines of history into myhistory, removing lines with "cd" command
grep -v "cd" ~/.bash_history | tail -n 250 > myhistory
🧪 Exercise 2 - Cron (Unix machines only)
Add a cron that recreate the root folder "personnages" at your user home each 5 min with a suffix number ( personnages_9h05, personnages_9h10...)
solution
crontab -e
*/5 * * * * /bin/bash /path/to/your/script.sh /root/folder/$(date +\%Y-\%m-\%d)
🧪 Exercise 3 - SystemD ( Linux machines only)
Add the script as a linux service with the same rule, each 5 min with a suffix number ( personnages_9h05, personnages_9h10...)
For MacOS
Use LaunchAgent or LaunchDaemon service implementation here
solution
/etc/systemd/system/folder_creation.service
[Unit]
Description=Folder Creation Service
After=network.target
[Service]
Type=oneshot
ExecStart=/bin/bash /path/to/your/script.sh /root/folder/$(date +\%Y-\%m-\%d)
[Install]
WantedBy=multi-user.target
/etc/systemd/system/folder_creation.timer
[Unit]
Description=Folder Creation Timer
[Timer]
OnUnitActiveSec=5m
Unit=folder_creation.service
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl start folder_creation.timer
sudo systemctl enable folder_creation.timer
🧪 Exercice 4 - Git
learn more about git
- Create an account on gitlab.com
- Create a project
- push this code to the project
🧪 Exercice 5 - onPremise Web server
Create an apache Web server and a MariaDB by pair with 2 laptops as follow. Serve a simple php content connected to the MariaDB with PDO
Use ping
, telnet
, ip
, netstat
during your services deployment
Some network recalls
What happens when you type a URL into your browser?
What Is REST API? Examples And How To Use It
(SSL, TLS, HTTPS Explained)
(HTTP/1 to HTTP/2 to HTTP/3)
solution
#!/bin/bash
# Update package index
sudo apt update
# Install Apache
sudo apt install -y apache2
# Start Apache service
sudo systemctl start apache2
# Enable Apache service to start on boot
sudo systemctl enable apache2
# Install Telnet
sudo apt install -y telnet
# Install Ping (usually pre-installed)
# If not installed, you can install with:
# sudo apt install -y iputils-ping
# Check Apache status
sudo systemctl status apache2
# Test Apache reachability
echo "Testing Apache reachability..."
if curl -s -I localhost:80 | grep "HTTP/1.1 200 OK" > /dev/null; then
echo "Apache is reachable."
else
echo "Apache is not reachable."
fi
# Test Telnet reachability
echo "Testing Telnet reachability..."
if telnet localhost 80 | grep "Escape character is" > /dev/null; then
echo "Telnet is reachable."
else
echo "Telnet is not reachable."
fi
# Test Ping reachability
echo "Testing Ping reachability..."
if ping -c 4 localhost | grep "4 packets transmitted, 4 received" > /dev/null; then
echo "Ping is reachable."
else
echo "Ping is not reachable."
fi
🧪 Exercise 6 - SSH
By pair create an ssh server on a laptop and try to connect from the other laptop.
solution
#!/bin/bash
# Update package index
sudo apt update
# Install OpenSSH server
sudo apt install -y openssh-server
# Start OpenSSH service
sudo systemctl start ssh
# Enable OpenSSH service to start on boot
sudo systemctl enable ssh
# Install Ping (if not already installed)
sudo apt install -y iputils-ping
# Replace 'remote_ip_address' with the IP address of the remote computer
remote_ip_address="REMOTE_IP_ADDRESS"
# Test Ping reachability to the remote computer
echo "Testing Ping reachability to $remote_ip_address ..."
if ping -c 4 $remote_ip_address | grep "4 packets transmitted, 4 received" > /dev/null; then
echo "Ping to $remote_ip_address is successful."
else
echo "Ping to $remote_ip_address failed."
exit 1
fi
# Attempt SSH connection to the remote computer
echo "Attempting SSH connection to $remote_ip_address ..."
if ssh $remote_ip_address -o ConnectTimeout=10 true; then
echo "SSH connection to $remote_ip_address successful."
else
echo "SSH connection to $remote_ip_address failed."
fi