reworking content
All checks were successful
learn org at code.softwareshinobi.com/linux.softwareshinobi.com/pipeline/head This commit looks good

This commit is contained in:
2025-06-19 10:03:08 -04:00
parent 611d0816cc
commit 7d9171c854
192 changed files with 2234 additions and 2362 deletions

View File

@@ -0,0 +1,91 @@
# About the book
* **This version was published on Oct 30 2023**
This is an open-source introduction to Bash scripting guide that will help you learn the basics of Bash scripting and start writing awesome Bash scripts that will help you automate your daily SysOps, DevOps, and Dev tasks. No matter if you are a DevOps/SysOps engineer, developer, or just a Linux enthusiast, you can use Bash scripts to combine different Linux commands and automate tedious and repetitive daily tasks so that you can focus on more productive and fun things.
The guide is suitable for anyone working as a developer, system administrator, or a DevOps engineer and wants to learn the basics of Bash scripting.
The first 13 chapters would be purely focused on getting some solid Bash scripting foundations, then the rest of the chapters would give you some real-life examples and scripts.
## About the author
My name is Bobby Iliev, and I have been working as a Linux DevOps Engineer since 2014. I am an avid Linux lover and supporter of the open-source movement philosophy. I am always doing that which I cannot do in order that I may learn how to do it, and I believe in sharing knowledge.
I think it's essential always to keep professional and surround yourself with good people, work hard, and be nice to everyone. You have to perform at a consistently higher level than others. That's the mark of a true professional.
For more information, please visit my blog at [https://bobbyiliev.com](https://bobbyiliev.com), follow me on Twitter [@bobbyiliev_](https://twitter.com/bobbyiliev_) and [YouTube](https://www.youtube.com/channel/UCQWmdHTeAO0UvaNqve9udRw).
## Sponsors
This book is made possible thanks to these fantastic companies!
### Materialize
The Streaming Database for Real-time Analytics.
[Materialize](https://materialize.com/) is a reactive database that delivers incremental view updates. Materialize helps developers easily build with streaming data using standard SQL.
### DigitalOcean
DigitalOcean is a cloud services platform delivering the simplicity developers love and businesses trust to run production applications at scale.
It provides highly available, secure, and scalable compute, storage, and networking solutions that help developers build great software faster.
Founded in 2012 with offices in New York and Cambridge, MA, DigitalOcean offers transparent and affordable pricing, an elegant user interface, and one of the largest libraries of open source resources available.
For more information, please visit [https://www.digitalocean.com](https://www.digitalocean.com) or follow [@digitalocean](https://twitter.com/digitalocean) on Twitter.
If you are new to DigitalOcean, you can get a free $200 credit and spin up your own servers via this referral link here:
[Free $200 Credit For DigitalOcean](https://m.do.co/c/2a9bba940f39)
### DevDojo
The DevDojo is a resource to learn all things web development and web design. Learn on your lunch break or wake up and enjoy a cup of coffee with us to learn something new.
Join this developer community, and we can all learn together, build together, and grow together.
[Join DevDojo](https://devdojo.com?ref=bobbyiliev)
For more information, please visit [https://www.devdojo.com](https://www.devdojo.com?ref=bobbyiliev) or follow [@thedevdojo](https://twitter.com/thedevdojo) on Twitter.
## Ebook PDF Generation Tool
This ebook was generated by [Ibis](https://github.com/themsaid/ibis/) developed by [Mohamed Said](https://github.com/themsaid).
Ibis is a PHP tool that helps you write eBooks in markdown.
## Ebook ePub Generation Tool
The ePub version was generated by [Pandoc](https://pandoc.org/).
## Book Cover
The cover for this ebook was created with [Canva.com](https://www.canva.com/join/determined-cork-learn).
If you ever need to create a graphic, poster, invitation, logo, presentation or anything that looks good — give Canva a go.
## License
MIT License
Copyright (c) 2020 Bobby Iliev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,11 @@
# Introduction to Bash scripting
Welcome to this Bash basics training guide! In this **bash crash course**, you will learn the **Bash basics** so you could start writing your own Bash scripts and automate your daily tasks.
Bash is a Unix shell and command language. It is widely available on various operating systems, and it is also the default command interpreter on most Linux systems.
Bash stands for Bourne-Again SHell. As with other shells, you can use Bash interactively directly in your terminal, and also, you can use Bash like any other programming language to write scripts. This book will help you learn the basics of Bash scripting including Bash Variables, User Input, Comments, Arguments, Arrays, Conditional Expressions, Conditionals, Loops, Functions, Debugging, and testing.
Bash scripts are great for automating repetitive workloads and can help you save time considerably. For example, imagine working with a group of five developers on a project that requires a tedious environment setup. In order for the program to work correctly, each developer has to manually set up the environment. That's the same and very long task (setting up the environment) repeated five times at least. This is where you and Bash scripts come to the rescue! So instead, you create a simple text file containing all the necessary instructions and share it with your teammates. And now, all they have to do is execute the Bash script and everything will be created for them.
In order to write Bash scripts, you just need a UNIX terminal and a text editor like Sublime Text, VS Code, or a terminal-based editor like vim or nano.

View File

@@ -0,0 +1,104 @@
# Working with Cloudflare API with Bash
I host all of my websites on **DigitalOcean** Droplets and I also use Cloudflare as my CDN provider. One of the benefits of using Cloudflare is that it reduces the overall traffic to your user and also hides your actual server IP address behind their CDN.
My personal favorite Cloudflare feature is their free DDoS protection. It has saved my servers multiple times from different DDoS attacks. They have a cool API that you could use to enable and disable their DDoS protection easily.
This chapter is going to be an exercise! I challenge you to go ahead and write a short bash script that would enable and disable the Cloudflare DDoS protection for your server automatically if needed!
## Prerequisites
Before following this guide here, please set up your Cloudflare account and get your website ready. If you are not sure how to do that you can follow these steps here: [Create a Cloudflare account and add a website](https://support.cloudflare.com/hc/en-us/articles/201720164-Step-2-Create-a-Cloudflare-account-and-add-a-website).
Once you have your Cloudflare account, make sure to obtain the following information:
* A Cloudflare account
* Cloudflare API key
* Cloudflare Zone ID
Also, Make sure curl is installed on your server:
```bash
curl --version
```
If curl is not installed you need to run the following:
* For RedHat/CentOs:
```bash
yum install curl
```
* For Debian/Ubuntu
```bash
apt-get install curl
```
## Challenge - Script requirements
The script needs to monitor the CPU usage on your server and if the CPU usage gets high based on the number vCPU it would enable the Cloudflare DDoS protection automatically via the Cloudflare API.
The main features of the script should be:
* Checks the script CPU load on the server
* In case of a CPU spike the script triggers an API call to Cloudflare and enables the DDoS protection feature for the specified zone
* After the CPU load is back to normal the script would disable the "I'm under attack" option and set it back to normal
## Example script
I already have prepared a demo script which you could use as a reference. But I encourage you to try and write the script yourself first and only then take a look at my script!
To download the script just run the following command:
```bash
wget https://raw.githubusercontent.com/bobbyiliev/cloudflare-ddos-protection/main/protection.sh
```
Open the script with your favorite text editor:
```bash
nano protection.sh
```
And update the following details with your Cloudflare details:
```bash
CF_CONE_ID=YOUR_CF_ZONE_ID
CF_EMAIL_ADDRESS=YOUR_CF_EMAIL_ADDRESS
CF_API_KEY=YOUR_CF_API_KEY
```
After that make the script executable:
```bash
chmod +x ~/protection.sh
```
Finally, set up 2 Cron jobs to run every 30 seconds. To edit your crontab run:
```bash
crontab -e
```
And add the following content:
```bash
* * * * * /path-to-the-script/cloudflare/protection.sh
* * * * * ( sleep 30 ; /path-to-the-script/cloudflare/protection.sh )
```
Note that you need to change the path to the script with the actual path where you've stored the script at.
## Conclusion
This is quite straight forward and budget solution, one of the downsides of the script is that if your server gets unresponsive due to an attack, the script might not be triggered at all.
Of course, a better approach would be to use a monitoring system like Nagios and based on the statistics from the monitoring system then you can trigger the script, but this script challenge could be a good learning experience!
Here is another great resource on how to use the Discord API and send notifications to your Discord Channel with a Bash script:
[How To Use Discord Webhooks to Get Notifications for Your Website Status on Ubuntu 18.04](https://www.digitalocean.com/community/tutorials/how-to-use-discord-webhooks-to-get-notifications-for-your-website-status-on-ubuntu-18-04)
>{notice} This content was initially posted on [DevDojo](https://devdojo.com/bobbyiliev/bash-script-to-automatically-enable-cloudflare-ddos-protection)

View File

@@ -0,0 +1,83 @@
# BASH Script parser to Summarize Your NGINX and Apache Access Logs
One of the first things that I would usually do in case I notice a high CPU usage on some of my Linux servers would be to check the process list with either top or htop and in case that I notice a lot of Apache or Nginx process I would quickly check my access logs to determine what has caused or is causing the CPU spike on my server or to figure out if anything malicious is going on.
Sometimes reading the logs could be quite intimidating as the log might be huge and going though it manually could take a lot of time. Also, the raw log format could be confusing for people with less experience.
Just like the previous chapter, this chapter is going to be a challenge! You need to write a short bash script that would summarize the whole access log for you without the need of installing any additional software.
# Script requirements
This BASH script needs to parse and summarize your access logs and provide you with very useful information like:
* The 20 top pages with the most POST requests
* The 20 top pages with the most GET requests
* Top 20 IP addresses and their geo-location
## Example script
I already have prepared a demo script which you could use as a reference. But I encourage you to try and write the script yourself first and only then take a look at my script!
In order to download the script, you can either clone the repository with the following command:
```bash
git clone https://github.com/bobbyiliev/quick_access_logs_summary.git
```
Or run the following command which would download the script in your current directory:
```bash
wget https://raw.githubusercontent.com/bobbyiliev/quick_access_logs_summary/master/spike_check
```
The script does not make any changes to your system, it only reads the content of your access log and summarizes it for you, however, once you've downloaded the file, make sure to review the content yourself.
## Running the script
All that you have to do once the script has been downloaded is to make it executable and run it.
To do that run the following command to make the script executable:
```bash
chmod +x spike_check
```
Then run the script:
```bash
./spike_check /path/to/your/access_log
```
Make sure to change the path to the file with the actual path to your access log. For example if you are using Apache on an Ubuntu server, the exact command would look like this:
```bash
./spike_check /var/log/apache2/access.log
```
If you are using Nginx the exact command would be almost the same, but with the path to the Nginx access log:
```bash
./spike_check /var/log/nginx/access.log
```
## Understanding the output
Once you run the script, it might take a while depending on the size of the log.
The output that you would see should look like this:
![Summarized access log](https://imgur.com/WWHVMrj.png)
Essentially what we can tell in this case is that we've received 16 POST requests to our xmlrpc.php file which is often used by attackers to try and exploit WordPress websites by using various username and password combinations.
In this specific case, this was not a huge brute force attack, but it gives us an early indication and we can take action to prevent a larger attack in the future.
We can also see that there were a couple of Russian IP addresses accessing our site, so in case that you do not expect any traffic from Russia, you might want to block those IP addresses as well.
## Conclusion
This is an example of a simple BASH script that allows you to quickly summarize your access logs and determine if anything malicious is going on.
Of course, you might want to also manually go through the logs as well but it is a good challenge to try and automate this with Bash!
>{notice} This content was initially posted on [DevDojo](https://devdojo.com/bobbyiliev/bash-script-to-summarize-your-nginx-and-apache-access-logs)

View File

@@ -0,0 +1,95 @@
# Sending emails with Bash and SSMTP
SSMTP is a tool that delivers emails from a computer or a server to a configured mail host.
SSMTP is not an email server itself and does not receive emails or manage a queue.
One of its primary uses is for forwarding automated email (like system alerts) off your machine and to an external email address.
## Prerequisites
You would need the following things in order to be able to complete this tutorial successfully:
* Access to an Ubuntu 18.04 server as a non-root user with sudo privileges and an active firewall installed on your server. To set these up, please refer to our [Initial Server Setup Guide for Ubuntu 18.04](https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-18-04)
* An SMTP server along with SMTP username and password, this would also work with Gmail's SMTP server, or you could set up your own SMTP server by following the steps from this tutorial on [How to Install and Configure Postfix as a Send-Only SMTP Server on Ubuntu 16.04](https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-postfix-as-a-send-only-smtp-server-on-ubuntu-16-04)
## Installing SSMTP
In order to install SSMTP, youll need to first update your apt cache with:
```bash
sudo apt update
```
Then run the following command to install SSMTP:
```bash
sudo apt install ssmtp
```
Another thing that you would need to install is `mailutils`, to do that run the following command:
```bash
sudo apt install mailutils
```
## Configuring SSMTP
Now that you have `ssmtp` installed, in order to configure it to use your SMTP server when sending emails, you need to edit the SSMTP configuration file.
Using your favourite text editor to open the `/etc/ssmtp/ssmtp.conf` file:
```bash
sudo nano /etc/ssmtp/ssmtp.conf
```
You need to include your SMTP configuration:
```
root=postmaster
mailhub=<^>your_smtp_host.com<^>:587
hostname=<^>your_hostname<^>
AuthUser=<^>your_gmail_username@your_smtp_host.com<^>
AuthPass=<^>your_gmail_password<^>
FromLineOverride=YES
UseSTARTTLS=YES
```
Save the file and exit.
## Sending emails with SSMTP
Once your configuration is done, in order to send an email just run the following command:
```bash
echo "<^>Here add your email body<^>" | mail -s "<^>Here specify your email subject<^>" <^>your_recepient_email@yourdomain.com<^>
```
You can run this directly in your terminal or include it in your bash scripts.
## Sending A File with SSMTP (optional)
If you need to send files as attachments, you can use `mpack`.
To install `mpack` run the following command:
```bash
sudo apt install mpack
```
Next, in order to send an email with a file attached, run the following command.
```bash
mpack -s "<^>Your Subject here<^>" your_file.zip <^>your_recepient_email@yourdomain.com<^>
```
The above command would send an email to `<^>your_recepient_email@yourdomain.com<^>` with the `<^>your_file.zip<^>` attached.
## Conclusion
SSMTP is a great and reliable way to implement SMTP email functionality directly in bash scripts.
For more information about SSMTP I would recommend checking the official documentation [here](https://wiki.archlinux.org/index.php/SSMTP).
>{notice} This content was initially posted on the [DigitalOcean community forum](https://www.digitalocean.com/community/questions/how-to-send-emails-from-a-bash-script-using-ssmtp).

View File

@@ -0,0 +1,126 @@
# Password Generator Bash Script
It's not uncommon situation where you will need to generate a random password that you can use for any software installation or when you sign-up to any website.
There are a lot of options in order to achieve this. You can use a password manager/vault where you often have the option to randomly generate a password or to use a website that can generate the password on your behalf.
You can also use Bash in your terminal (command-line) to generate a password that you can quickly use. There are a lot of ways to achieve that and I will make sure to cover few of them and will leave up to you to choose which option is most suitable with your needs.
## :warning: Security
**This script is intended to practice your bash scripting skills. You can have fun while doing simple projects with BASH, but security is not a joke, so please make sure you do not save your passwords in plain text in a local file or write them down by hand on a piece of paper.**
**I will highly recommend everyone to use secure and trusted providers to generate and save the passwords.**
## Script summary
Let me first do a quick summary of what our script is going to do.:
1. We will have to option to choose the password characters length when the script is executed.
2. The script will then generate 5 random passwords with the length that was specified in step 1
## Prerequisites
You would need a bash terminal and a text editor. You can use any text editor like vi, vim, nano or Visual Studio Code.
I'm running the script locally on my Linux laptop but if you're using Windows PC you can ssh to any server of your choice and execute the script there.
Although the script is pretty simple, having some basic BASH scripting knowledge will help you to better understand the script and how it's working.
## Generate a random password
One of the great benefits of Linux is that you can do a lot of things using different methods. When it comes to generating a random string of characters it's not different as well.
You can use several commands in order to generate a random string of characters. I will cover few of them and will provide some examples.
- Using the ```date``` command.
The date command will output the current date and time. However we also further manipulate the output in order to use it as randomly generated password. We can hash the date using md5, sha or just run it through base64. These are few examples:
```
date | md5sum
94cb1cdecfed0699e2d98acd9a7b8f6d -
```
using sha256sum:
```
date | sha256sum
30a0c6091e194c8c7785f0d7bb6e1eac9b76c0528f02213d1b6a5fbcc76ceff4 -
```
using base64:
```
date | base64
0YHQsSDRj9C90YMgMzAgMTk6NTE6NDggRUVUIDIwMjEK
```
- We can also use openssl in order to generate pseudo-random bytes and run the output through base64. An example output will be:
```
openssl rand -base64 10
9+soM9bt8mhdcw==
```
Keep in mind that openssl might not be installed on your system so it's likely that you will need to install it first in order to use it.
- The most preferred way is to use the pseudorandom number generator - /dev/urandom
since it is intended for most cryptographic purposes. We would also need to manipulate the output using ```tr``` in order to translate it. An example command is:
```
tr -cd '[:alnum:]' < /dev/urandom | fold -w10 | head -n 1
```
With this command we take the output from /dev/urandom and translate it with ```tr``` while using all letters and digits and print the desired number of characters.
## The script
First we begin the script with the shebang. We use it to tell the operating system which interpreter to use to parse the rest of the file.
```
#!/bin/bash
```
We can then continue and ask the user for some input. In this case we would like to know how many characters the password needs to be:
```
# Ask user for password length
clear
printf "\n"
read -p "How many characters you would like the password to have? " pass_length
printf "\n"
```
Generate the passwords and then print it so the user can use it.
```
# This is where the magic happens!
# Generate a list of 10 strings and cut it to the desired value provided from the user
for i in {1..10}; do (tr -cd '[:alnum:]' < /dev/urandom | fold -w${pass_length} | head -n 1); done
# Print the strings
printf "$pass_output\n"
printf "Goodbye, ${USER}\n"
```
## The full script:
```
#!/bin/bash
#=======================================
# Password generator with login option
#=======================================
# Ask user for the string length
clear
printf "\n"
read -p "How many characters you would like the password to have? " pass_length
printf "\n"
# This is where the magic happens!
# Generate a list of 10 strings and cut it to the desired value provided from the user
for i in {1..10}; do (tr -cd '[:alnum:]' < /dev/urandom | fold -w${pass_length} | head -n 1); done
# Print the strings
printf "$pass_output\n"
printf "Goodbye, ${USER}\n"
```
## Conclusion
This is pretty much how you can use simple bash script to generate random passwords.
:warning: **As already mentioned, please make sure to use strong passwords in order to make sure your account is protected. Also whenever is possible use 2 factor authentication as this will provide additional layer of security for your account.**
While the script is working fine, it expects that the user will provide the requested input. In order to prevent any issues you would need to do some more advance checks on the user input in order to make sure the script will continue to work fine even if the provided input does not match our needs.
## Contributed by
[Alex Georgiev](https://twitter.com/alexgeorgiev17)

View File

@@ -0,0 +1,336 @@
# Automatic WordPress on LAMP installation with BASH
Here is an example of a full LAMP and WordPress installation that works on any Debian-based machine.
# Prerequisites
- A Debian-based machine (Ubuntu, Debian, Linux Mint, etc.)
# Planning the functionality
Let's start again by going over the main functionality of the script:
**Lamp Installation**
* Update the package manager
* Install a firewall (ufw)
* Allow SSH, HTTP and HTTPS traffic
* Install Apache2
* Install & Configure MariaDB
* Install PHP and required plugins
* Enable all required Apache2 mods
**Apache Virtual Host Setup**
* Create a directory in `/var/www`
* Configure permissions to the directory
* Create the `$domain` file under `/etc/apache2/sites-available` and append the required Virtualhost content
* Enable the site
* Restart Apache2
**SSL Config**
* Generate the OpenSSL certificate
* Append the SSL certificate to the `ssl-params.conf` file
* Append the SSL config to the Virtualhost file
* Enable SSL
* Reload Apache2
**Database Config**
* Create a database
* Create a user
* Flush Privileges
**WordPress Config**
* Install required WordPress PHP plugins
* Install WordPress
* Append the required information to `wp-config.php` file
Without further ado, let's start writing the script.
# The script
We start by setting our variables and asking the user to input their domain:
```bash
echo 'Please enter your domain of preference without www:'
read DOMAIN
echo "Please enter your Database username:"
read DBUSERNAME
echo "Please enter your Database password:"
read DBPASSWORD
echo "Please enter your Database name:"
read DBNAME
ip=`hostname -I | cut -f1 -d' '`
```
We are now ready to start writing our functions. Start by creating the `lamp_install()` function. Inside of it, we are going to update the system, install ufw, allow SSH, HTTP and HTTPS traffic, install Apache2, install MariaDB and PHP. We are also going to enable all required Apache2 mods.
```bash
lamp_install () {
apt update -y
apt install ufw
ufw enable
ufw allow OpenSSH
ufw allow in "WWW Full"
apt install apache2 -y
apt install mariadb-server
mysql_secure_installation -y
apt install php libapache2-mod-php php-mysql -y
sed -i "2d" /etc/apache2/mods-enabled/dir.conf
sed -i "2i\\\tDirectoryIndex index.php index.html index.cgi index.pl index.xhtml index.htm" /etc/apache2/mods-enabled/dir.conf
systemctl reload apache2
}
```
Next, we are going to create the `apache_virtualhost_setup()` function. Inside of it, we are going to create a directory in `/var/www`, configure permissions to the directory, create the `$domain` file under `/etc/apache2/sites-available` and append the required Virtualhost content, enable the site and restart Apache2.
```bash
apache_virtual_host_setup () {
mkdir /var/www/$DOMAIN
chown -R $USER:$USER /var/www/$DOMAIN
echo "<VirtualHost *:80>" >> /etc/apache2/sites-available/$DOMAIN.conf
echo -e "\tServerName $DOMAIN" >> /etc/apache2/sites-available/$DOMAIN.conf
echo -e "\tServerAlias www.$DOMAIN" >> /etc/apache2/sites-available/$DOMAIN.conf
echo -e "\tServerAdmin webmaster@localhost" >> /etc/apache2/sites-available/$DOMAIN.conf
echo -e "\tDocumentRoot /var/www/$DOMAIN" >> /etc/apache2/sites-available/$DOMAIN.conf
echo -e '\tErrorLog ${APACHE_LOG_DIR}/error.log' >> /etc/apache2/sites-available/$DOMAIN.conf
echo -e '\tCustomLog ${APACHE_LOG_DIR}/access.log combined' >> /etc/apache2/sites-available/$DOMAIN.conf
echo "</VirtualHost>" >> /etc/apache2/sites-available/$DOMAIN.conf
a2ensite $DOMAIN
a2dissite 000-default
systemctl reload apache2
}
```
Next, we are going to create the `ssl_config()` function. Inside of it, we are going to generate the OpenSSL certificate, append the SSL certificate to the `ssl-params.conf` file, append the SSL config to the Virtualhost file, enable SSL and reload Apache2.
```bash
ssl_config () {
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/apache-selfsigned.key -out /etc/ssl/certs/apache-selfsigned.crt
echo "SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH" >> /etc/apache2/conf-available/ssl-params.conf
echo "SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1" >> /etc/apache2/conf-available/ssl-params.conf
echo "SSLHonorCipherOrder On" >> /etc/apache2/conf-available/ssl-params.conf
echo "Header always set X-Frame-Options DENY" >> /etc/apache2/conf-available/ssl-params.conf
echo "Header always set X-Content-Type-Options nosniff" >> /etc/apache2/conf-available/ssl-params.conf
echo "SSLCompression off" >> /etc/apache2/conf-available/ssl-params.conf
echo "SSLUseStapling on" >> /etc/apache2/conf-available/ssl-params.conf
echo "SSLStaplingCache \"shmcb:logs/stapling-cache(150000)\"" >> /etc/apache2/conf-available/ssl-params.conf
echo "SSLSessionTickets Off" >> /etc/apache2/conf-available/ssl-params.conf
cp /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-available/default-ssl.conf.bak
sed -i "s/var\/www\/html/var\/www\/$DOMAIN/1" /etc/apache2/sites-available/default-ssl.conf
sed -i "s/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/etc\/ssl\/certs\/apache-selfsigned.crt/1" /etc/apache2/sites-available/default-ssl.conf
sed -i "s/etc\/ssl\/private\/ssl-cert-snakeoil.key/etc\/ssl\/private\/apache-selfsigned.key/1" /etc/apache2/sites-available/default-ssl.conf
sed -i "4i\\\t\tServerName $ip" /etc/apache2/sites-available/default-ssl.conf
sed -i "22i\\\tRedirect permanent \"/\" \"https://$ip/\"" /etc/apache2/sites-available/000-default.conf
a2enmod ssl
a2enmod headers
a2ensite default-ssl
a2enconf ssl-params
systemctl reload apache2
}
```
Next, we are going to create the `db_setup()` function. Inside of it, we are going to create the database, create the user and grant all privileges to the user.
```bash
db_config () {
mysql -e "CREATE DATABASE $DBNAME;"
mysql -e "GRANT ALL ON $DBNAME.* TO '$DBUSERNAME'@'localhost' IDENTIFIED BY '$DBPASSWORD' WITH GRANT OPTION;"
mysql -e "FLUSH PRIVILEGES;"
}
```
Next, we are going to create the `wordpress_config()` function. Inside of it, we are going to download the latest version of WordPress, extract it to the `/var/www/$DOMAIN` directory, create the `wp-config.php` file and append the required content to it.
```bash
wordpress_config () {
db_config
apt install php-curl php-gd php-mbstring php-xml php-xmlrpc php-soap php-intl php-zip -y
systemctl restart apache2
sed -i "8i\\\t<Directory /var/www/$DOMAIN/>" /etc/apache2/sites-available/$DOMAIN.conf
sed -i "9i\\\t\tAllowOverride All" /etc/apache2/sites-available/$DOMAIN.conf
sed -i "10i\\\t</Directory>" /etc/apache2/sites-available/$DOMAIN.conf
a2enmod rewrite
systemctl restart apache2
apt install curl
cd /tmp
curl -O https://wordpress.org/latest.tar.gz
tar xzvf latest.tar.gz
touch /tmp/wordpress/.htaccess
cp /tmp/wordpress/wp-config-sample.php /tmp/wordpress/wp-config.php
mkdir /tmp/wordpress/wp-content/upgrade
cp -a /tmp/wordpress/. /var/www/$DOMAIN
chown -R www-data:www-data /var/www/$DOMAIN
find /var/www/$DOMAIN/ -type d -exec chmod 750 {} \;
find /var/www/$DOMAIN/ -type f -exec chmod 640 {} \;
curl -s https://api.wordpress.org/secret-key/1.1/salt/ >> /var/www/$DOMAIN/wp-config.php
echo "define('FS_METHOD', 'direct');" >> /var/www/$DOMAIN/wp-config.php
sed -i "51,58d" /var/www/$DOMAIN/wp-config.php
sed -i "s/database_name_here/$DBNAME/1" /var/www/$DOMAIN/wp-config.php
sed -i "s/username_here/$DBUSERNAME/1" /var/www/$DOMAIN/wp-config.php
sed -i "s/password_here/$DBPASSWORD/1" /var/www/$DOMAIN/wp-config.php
}
```
And finally, we are going to create the `execute()` function. Inside of it, we are going to call all the functions we created above.
```bash
execute () {
lamp_install
apache_virtual_host_setup
ssl_config
wordpress_config
}
```
With this, you have the script ready and you are ready to run it. And if you need the full script, you can find it in the next section.
# The full script
```bash
#!/bin/bash
echo 'Please enter your domain of preference without www:'
read DOMAIN
echo "Please enter your Database username:"
read DBUSERNAME
echo "Please enter your Database password:"
read DBPASSWORD
echo "Please enter your Database name:"
read DBNAME
ip=`hostname -I | cut -f1 -d' '`
lamp_install () {
apt update -y
apt install ufw
ufw enable
ufw allow OpenSSH
ufw allow in "WWW Full"
apt install apache2 -y
apt install mariadb-server
mysql_secure_installation -y
apt install php libapache2-mod-php php-mysql -y
sed -i "2d" /etc/apache2/mods-enabled/dir.conf
sed -i "2i\\\tDirectoryIndex index.php index.html index.cgi index.pl index.xhtml index.htm" /etc/apache2/mods-enabled/dir.conf
systemctl reload apache2
}
apache_virtual_host_setup () {
mkdir /var/www/$DOMAIN
chown -R $USER:$USER /var/www/$DOMAIN
echo "<VirtualHost *:80>" >> /etc/apache2/sites-available/$DOMAIN.conf
echo -e "\tServerName $DOMAIN" >> /etc/apache2/sites-available/$DOMAIN.conf
echo -e "\tServerAlias www.$DOMAIN" >> /etc/apache2/sites-available/$DOMAIN.conf
echo -e "\tServerAdmin webmaster@localhost" >> /etc/apache2/sites-available/$DOMAIN.conf
echo -e "\tDocumentRoot /var/www/$DOMAIN" >> /etc/apache2/sites-available/$DOMAIN.conf
echo -e '\tErrorLog ${APACHE_LOG_DIR}/error.log' >> /etc/apache2/sites-available/$DOMAIN.conf
echo -e '\tCustomLog ${APACHE_LOG_DIR}/access.log combined' >> /etc/apache2/sites-available/$DOMAIN.conf
echo "</VirtualHost>" >> /etc/apache2/sites-available/$DOMAIN.conf
a2ensite $DOMAIN
a2dissite 000-default
systemctl reload apache2
}
ssl_config () {
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/apache-selfsigned.key -out /etc/ssl/certs/apache-selfsigned.crt
echo "SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH" >> /etc/apache2/conf-available/ssl-params.conf
echo "SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1" >> /etc/apache2/conf-available/ssl-params.conf
echo "SSLHonorCipherOrder On" >> /etc/apache2/conf-available/ssl-params.conf
echo "Header always set X-Frame-Options DENY" >> /etc/apache2/conf-available/ssl-params.conf
echo "Header always set X-Content-Type-Options nosniff" >> /etc/apache2/conf-available/ssl-params.conf
echo "SSLCompression off" >> /etc/apache2/conf-available/ssl-params.conf
echo "SSLUseStapling on" >> /etc/apache2/conf-available/ssl-params.conf
echo "SSLStaplingCache \"shmcb:logs/stapling-cache(150000)\"" >> /etc/apache2/conf-available/ssl-params.conf
echo "SSLSessionTickets Off" >> /etc/apache2/conf-available/ssl-params.conf
cp /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-available/default-ssl.conf.bak
sed -i "s/var\/www\/html/var\/www\/$DOMAIN/1" /etc/apache2/sites-available/default-ssl.conf
sed -i "s/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/etc\/ssl\/certs\/apache-selfsigned.crt/1" /etc/apache2/sites-available/default-ssl.conf
sed -i "s/etc\/ssl\/private\/ssl-cert-snakeoil.key/etc\/ssl\/private\/apache-selfsigned.key/1" /etc/apache2/sites-available/default-ssl.conf
sed -i "4i\\\t\tServerName $ip" /etc/apache2/sites-available/default-ssl.conf
sed -i "22i\\\tRedirect permanent \"/\" \"https://$ip/\"" /etc/apache2/sites-available/000-default.conf
a2enmod ssl
a2enmod headers
a2ensite default-ssl
a2enconf ssl-params
systemctl reload apache2
}
db_config () {
mysql -e "CREATE DATABASE $DBNAME;"
mysql -e "GRANT ALL ON $DBNAME.* TO '$DBUSERNAME'@'localhost' IDENTIFIED BY '$DBPASSWORD' WITH GRANT OPTION;"
mysql -e "FLUSH PRIVILEGES;"
}
wordpress_config () {
db_config
apt install php-curl php-gd php-mbstring php-xml php-xmlrpc php-soap php-intl php-zip -y
systemctl restart apache2
sed -i "8i\\\t<Directory /var/www/$DOMAIN/>" /etc/apache2/sites-available/$DOMAIN.conf
sed -i "9i\\\t\tAllowOverride All" /etc/apache2/sites-available/$DOMAIN.conf
sed -i "10i\\\t</Directory>" /etc/apache2/sites-available/$DOMAIN.conf
a2enmod rewrite
systemctl restart apache2
apt install curl
cd /tmp
curl -O https://wordpress.org/latest.tar.gz
tar xzvf latest.tar.gz
touch /tmp/wordpress/.htaccess
cp /tmp/wordpress/wp-config-sample.php /tmp/wordpress/wp-config.php
mkdir /tmp/wordpress/wp-content/upgrade
cp -a /tmp/wordpress/. /var/www/$DOMAIN
chown -R www-data:www-data /var/www/$DOMAIN
find /var/www/$DOMAIN/ -type d -exec chmod 750 {} \;
find /var/www/$DOMAIN/ -type f -exec chmod 640 {} \;
curl -s https://api.wordpress.org/secret-key/1.1/salt/ >> /var/www/$DOMAIN/wp-config.php
echo "define('FS_METHOD', 'direct');" >> /var/www/$DOMAIN/wp-config.php
sed -i "51,58d" /var/www/$DOMAIN/wp-config.php
sed -i "s/database_name_here/$DBNAME/1" /var/www/$DOMAIN/wp-config.php
sed -i "s/username_here/$DBUSERNAME/1" /var/www/$DOMAIN/wp-config.php
sed -i "s/password_here/$DBPASSWORD/1" /var/www/$DOMAIN/wp-config.php
}
execute () {
lamp_install
apache_virtual_host_setup
ssl_config
wordpress_config
}
```
## Summary
The script does the following:
* Install LAMP
* Create a virtual host
* Configure SSL
* Install WordPress
* Configure WordPress
With this being said, I hope you enjoyed this example. If you have any questions, please feel free to ask me directly at [@denctl](https://twitter.com/denctl).

View File

@@ -0,0 +1,15 @@
# Wrap Up
Congratulations! You have just completed the Bash basics guide!
If you found this useful, be sure to star the project on [GitHub](https://github.com/bobbyiliev/introduction-to-bash-scripting)!
If you have any suggestions for improvements, make sure to contribute pull requests or open issues.
In this introduction to Bash scripting book, we just covered the basics, but you still have enough under your belt to start wringing some awesome scripts and automating daily tasks!
As a next step try writing your own script and share it with the world! This is the best way to learn any new programming or scripting language!
In case that this book inspired you to write some cool Bash scripts, make sure to tweet about it and tag [@bobbyiliev_](https://twitter.com) so that we could check it out!
Congrats again on completing this book!

View File

@@ -0,0 +1,23 @@
# Bash Basics
To begin, create a new file with a `.sh` extension. We'll use `shinobi.sh` as our example.
You can create it instantly with `touch`:
```bash
touch shinobi.sh
```
Or, open it directly in your text editor:
```bash
nano shinobi.sh
```
For your script to execute, the very first line must specify the interpreter. This is called the Shebang. While `#!/bin/bash` instructs the operating system to use `/bin/bash`, its location can vary. For wider compatibility, use this:
```bash
#!/usr/bin/env bash
```
This tells the system to find `bash` within your `PATH` environment variable, ensuring your script runs consistently across different systems.

View File

@@ -0,0 +1,45 @@
# Hello World Bash
Let's build your first script. Create `shinobi.sh` and add the essential shebang, followed by your `Hello World` message:
```bash
touch shinobi.sh
```
Now, open `shinobi.sh` and add this content:
```bash
#!/usr/bin/env bash
echo "Hello World!"
```
Save and close the file.
Next, make your script executable:
```bash
chmod +x shinobi.sh
```
Execute your script directly:
```bash
./shinobi.sh
```
You'll see "Hello World!" printed.
Alternatively, you can run the script by explicitly calling the `bash` interpreter:
```bash
bash shinobi.sh
```
For quick tests, `echo` works directly in your terminal:
```bash
echo "Hello Shinobi!"
```
Scripts become powerful when combining multiple commands for automated tasks. This is your first step.

View File

@@ -0,0 +1,121 @@
# Variables
Like any language, Bash uses variables. No strict data types here; a variable holds numbers or characters.
Assign a value:
```bash
name="Shinobi"
```
> **Note:** No spaces around the `=` sign. This is critical.
Access the value using `$` before the variable name:
```bash
echo $name
```
While optional, wrapping the name in curly braces is good practice for clarity:
```bash
echo ${name}
```
Both would output: `Shinobi`.
Now, let's build a script.
First, create the file:
```bash
touch shinobi.sh
```
Then, open `shinobi.sh` and add this content to include a variable:
```bash
#!/usr/bin/env bash
name="Shinobi"
echo "Hi there $name"
```
Save and exit.
Make it executable:
```bash
chmod +x shinobi.sh
```
Run your script:
```bash
./shinobi.sh
```
You'll see:
```bash
Hi there Shinobi
```
This script:
* `#!/usr/bin/env bash`: Sets the interpreter.
* `name="Shinobi"`: Defines `name` with its value.
* `echo "Hi there $name"`: Outputs the welcome message using the variable.
You can use multiple variables:
```bash
#!/usr/bin/env bash
name="Shinobi"
greeting="Hello"
echo "$greeting $name"
```
Save and run `shinobi.sh` again:
```bash
./shinobi.sh
```
Output:
```bash
Hello Shinobi
```
No semicolons needed at line ends.
### Command Line Parameters
Bash scripts also read variables passed directly from the command line. These are called parameters.
Run your script with inputs like this:
```bash
./shinobi.sh Troy buddy!
```
Now, modify your `shinobi.sh` file to access these parameters:
```bash
#!/usr/bin/env bash
echo "Hello there" $1 # $1: first parameter
echo "Hello there" $2 # $2: second parameter
echo "Hello there" $@ # $@: all parameters
```
The output for `./shinobi.sh Troy buddy!` will be:
```bash
Hello there Troy
Hello there buddy!
Hello there Troy buddy!
```

View File

@@ -0,0 +1,64 @@
# User Input
You've outputted variable values. Now, let's get input from the user.
First, create your script file:
```bash
touch shinobi.sh
```
Next, open `shinobi.sh` and add this:
```bash
#!/usr/bin/env bash
echo "What is your name?"
read name
echo "Hi there $name"
echo "Welcome to Shinobi!"
```
Save and exit the file.
Make it executable:
```bash
chmod +x shinobi.sh
```
Run your script:
```bash
./shinobi.sh
```
The script will prompt you:
```
What is your name?
Troy
```
Enter a name (e.g., `Troy`) and hit Enter. You'll see:
```
Hi there Troy
Welcome to Shinobi!
```
This script prompts the user, stores their input in the `name` variable, then uses it to print a personalized message.
### Streamlined Input
To reduce lines, use `read` with the `-p` flag. This prints a prompt before waiting for input:
```bash
#!/usr/bin/env bash
read -p "What is your name? " name
echo "Hi there $name"
echo "Welcome to Shinobi!"
```

View File

@@ -0,0 +1,40 @@
# Comments
Add comments to your Bash scripts for notes and clarity. Lines starting with `#` are ignored by the interpreter.
```bash
# This is a comment. It will not run.
```
Let's create a new script, `shinobi.sh`, and include comments:
```bash
touch shinobi.sh
```
Now, open `shinobi.sh` and add this:
```bash
#!/usr/bin/env bash
# Ask the user for their name
read -p "What is your name? " name
# Greet the user
echo "Hi there $name"
echo "Welcome to Dev Team Six!"
```
Save and exit.
Make your script executable and run it:
```bash
chmod +x shinobi.sh
./shinobi.sh
```
Comments are essential. They make your code readable, for yourself and for anyone else who works on it. Clarity drives efficiency.

View File

@@ -0,0 +1,101 @@
# Runtime Arguments
Pass data into your script at execution. Arguments follow the script name:
```bash
./your_script.sh first_argument
```
Inside the script, `$1` references the first argument, `$2` the second, and so on.
Let's see this in `arguments.sh`:
```bash
touch arguments.sh
```
Open `arguments.sh` and add:
```bash
#!/usr/bin/env bash
echo "Arg 1: $1"
echo "Arg 2: $2"
echo "Arg 3: $3"
```
Save and exit. Make it executable:
```bash
chmod +x arguments.sh
```
Run with three arguments:
```bash
./arguments.sh dog cat bird
```
Output:
```bash
Arg 1: dog
Arg 2: cat
Arg 3: bird
```
To access *all* arguments, use `$@`. Update `arguments.sh`:
```bash
#!/usr/bin/env bash
echo "All arguments: $@"
```
Save. Run again with arguments:
```bash
./arguments.sh dog cat bird
```
Output:
```bash
All arguments: dog cat bird
```
### Script Name (`$0`)
`$0` references the script itself. This is useful for logging or unique operations.
You can even use `$0` for self-deletion. **Handle with extreme caution!**
Create `self_destruct.sh`:
```bash
touch self_destruct.sh
```
Open `self_destruct.sh` and add:
```bash
#!/usr/bin/env bash
echo "This script: $0 is self-destructing."
rm -f $0
```
Save and exit. Make it executable:
```bash
chmod +x self_destruct.sh
```
Run it:
```bash
./self_destruct.sh
```
The script will print its name, then delete itself. **This is irreversible. No second chances.** Always back up before testing self-deletion.

View File

@@ -0,0 +1,97 @@
# Arrays
Arrays are essential. They let a single variable hold multiple values. Initialize them by listing values, separated by spaces, inside parentheses:
```bash
# Example initialization:
my_array=("value 1" "value 2" "value 3" "value 4")
```
Access array elements using their numeric index. **Always use curly brackets.**
Let's create `arrays.sh` to demonstrate:
```bash
touch arrays.sh
```
Now, open `arrays.sh` and add:
```bash
#!/usr/bin/env bash
my_array=("value 1" "value 2" "value 3" "value 4")
echo "Second element (index 1): ${my_array[1]}"
echo "Last element (index -1): ${my_array[-1]}"
echo "All elements: ${my_array[@]}"
echo "Total elements: ${#my_array[@]}"
```
Save and exit. Make it executable:
```bash
chmod +x arrays.sh
```
Run your script:
```bash
./arrays.sh
```
Output:
```
value 2
value 4
value 1 value 2 value 3 value 4
4
```
### Slicing
Extract specific portions of an array or string using slicing notation.
Create `slicing.sh`:
```bash
touch slicing.sh
```
Open `slicing.sh` and add these examples:
```bash
#!/usr/bin/env bash
letters=("A" "B" "C" "D" "E")
echo "Original array: ${letters[@]}"
echo "Example 1 (start 0, length 2): ${letters:0:2}" # Prints AB
echo "Example 2 (start 0, all elements): ${letters::5}" # Prints ABCDE
echo "Example 3 (start 3, to end): ${letters:3}" # Prints DE
```
Save and exit. Make it executable:
```bash
chmod +x slicing.sh
```
Run `slicing.sh`:
```bash
./slicing.sh
```
Output:
```
A B C D E
AB
ABCDE
DE
```
Mastering arrays and slicing gives you precise control over your data structures.

View File

@@ -0,0 +1,110 @@
# Conditional Expressions
Conditionals are how your scripts make decisions: run different code based on a true/false outcome.
In Bash, `[[` is your go-to for testing files, strings, and numbers.
Let's start with a basic example:
```bash
touch conditional_test.sh
```
Open `conditional_test.sh` and add:
```bash
#!/usr/bin/env bash
my_var="data"
if [[ -n "$my_var" ]]; then # If variable is not empty
echo "Variable contains data."
fi
```
Save, make executable, and run:
```bash
chmod +x conditional_test.sh
./conditional_test.sh
```
Output: `Variable contains data.`
Now, for your full reference:
## File Tests
These check file attributes. Use `"${file}"` to handle spaces in names.
* `[[ -e "${file}" ]]` - True if `file` exists.
* `[[ -f "${file}" ]]` - True if `file` exists and is a regular file.
* `[[ -d "${file}" ]]` - True if `file` exists and is a directory.
* `[[ -s "${file}" ]]` - True if `file` exists and is not empty (size > 0).
* `[[ -r "${file}" ]]` - True if `file` exists and is readable.
* `[[ -w "${file}" ]]` - True if `file` exists and is writable.
* `[[ -x "${file}" ]]` - True if `file` exists and is executable.
* `[[ -L "${file}" ]]` - True if `file` is a symbolic link (`-h` is also used).
* `[[ -b "${file}" ]]` - True if `file` exists and is a block device.
* `[[ -c "${file}" ]]` - True if `file` exists and is a character device.
## String Tests
Compare string properties and values.
* `[[ -v "${varname}" ]]` - True if `varname` is set (has a value).
* `[[ -z "${string}" ]]` - True if `string` has zero length (empty).
* `[[ -n "${string}" ]]` - True if `string` has non-zero length (not empty).
* `[[ "${string1}" == "${string2}" ]]` - True if strings are equal. (`==` allows pattern matching inside `[[`.)
* `[[ "${string1}" != "${string2}" ]]` - True if strings are not equal.
* `[[ "${string1}" < "${string2}" ]]` - True if `string1` sorts before `string2` lexicographically.
* `[[ "${string1}" > "${string2}" ]]` - True if `string1` sorts after `string2` lexicographically.
## Numeric Comparisons
Compare integer values.
* `[[ ${arg1} -eq ${arg2} ]]` - True if `arg1` equals `arg2`.
* `[[ ${arg1} -ne ${arg2} ]]` - True if `arg1` not equals `arg2`.
* `[[ ${arg1} -lt ${arg2} ]]` - True if `arg1` less than `arg2`.
* `[[ ${arg1} -le ${arg2} ]]` - True if `arg1` less than or equal to `arg2`.
* `[[ ${arg1} -gt ${arg2} ]]` - True if `arg1` greater than `arg2`.
* `[[ ${arg1} -ge ${arg2} ]]` - True if `arg1` greater than or equal to `arg2`.
## Logical Operators
Combine multiple conditions.
* **AND (`&&`)**: Both conditions must be true.
```bash
# Example: file exists AND is not empty
if [[ -f "my_file.txt" && -s "my_file.txt" ]]; then
echo "File is present and has content."
fi
```
* **OR (`||`)**: At least one condition must be true.
```bash
# Example: either file or directory exists
if [[ -f "another_file.txt" || -d "another_dir" ]]; then
echo "Found a file or a directory."
fi
```
## Exit Status Checks
`$?:` The exit status of the *last* executed command. `0` means success. Any non-zero value indicates an error.
* **Success:**
```bash
command_to_run
if [[ $? -eq 0 ]]; then
echo "Command succeeded."
fi
```
* **Failure:**
```bash
command_to_run
if [[ $? -ne 0 ]]; then
echo "Command failed."
fi
```

View File

@@ -0,0 +1,237 @@
# Conditionals
You've mastered conditional expressions. Now, let's put them to work using `if`, `if-else`, `elif`, and `case` statements to control your script's flow.
---
### If Statements
The `if` statement executes commands only if a condition is true.
```bash
if [[ some_test ]]
then
<commands>
fi
```
Example: Prompt for a name, then check if it's empty.
```bash
touch if_example.sh
```
Open `if_example.sh` and add:
```bash
#!/usr/bin/env bash
read -p "What is your name? " name
if [[ -z "${name}" ]]; then # Check if name is empty
echo "Please enter your name!"
fi
```
Save and exit. Make it executable and run:
```bash
chmod +x if_example.sh
./if_example.sh
```
### If-Else Statements
Use `else` to define actions when the `if` condition is false.
Create `if_else_example.sh`:
```bash
touch if_else_example.sh
```
Open `if_else_example.sh` and add:
```bash
#!/usr/bin/env bash
read -p "What is your name? " name
if [[ -z "${name}" ]]; then
echo "Please enter your name!"
else
echo "Hi there ${name}!"
fi
```
Save, make executable, and run.
### Admin/Root Checks
Check user roles. For admin verification:
Create `admin_check.sh`:
```bash
touch admin_check.sh
```
Open `admin_check.sh` and add:
```bash
#!/usr/bin/env bash
admin="Dev Team Six"
read -p "Enter your username: " username
if [[ "${username}" == "${admin}" ]]; then
echo "You are the admin user!"
else
echo "You are NOT the admin user!"
fi
```
Save, make executable, and run.
To prevent a script from running as `root` (`EUID` is 0 for root):
Create `root_check.sh`:
```bash
touch root_check.sh
```
Open `root_check.sh` and add:
```bash
#!/usr/bin/env bash
if [[ $EUID -eq 0 ]]; then # Check if current user ID is 0 (root)
echo "This script should not be run as root. Exiting."
exit 1 # Exit with error code
fi
echo "Script running as non-root user."
```
Save, make executable, and run (test as root and non-root).
Combine conditions for stricter control. This example ensures the user is neither `admin` nor `root`.
Create `combined_check.sh`:
```bash
touch combined_check.sh
```
Open `combined_check.sh` and add:
```bash
#!/usr/bin/env bash
admin_user="Dev Team Six"
read -p "Enter your username: " username
if [[ "${username}" != "${admin_user}" || $EUID -ne 0 ]]; then # OR operator
echo "You are not the admin or root user. Proceeding safely."
else
echo "You are an admin or root user. Exercise caution."
fi
```
Save, make executable, and run.
### Elif Statements
For multiple, mutually exclusive conditions, use `elif`.
Create `elif_example.sh`:
```bash
touch elif_example.sh
```
Open `elif_example.sh` and add:
```bash
#!/usr/bin/env bash
read -p "Enter a number: " num
if [[ $num -gt 0 ]]; then
echo "The number is positive."
elif [[ $num -lt 0 ]]; then
echo "The number is negative."
else
echo "The number is 0."
fi
```
Save, make executable, and run.
### Case Statements
Simplify complex conditionals with `case` when you have multiple choices.
The `case` syntax:
```bash
case $variable_to_test in
pattern_1)
commands_for_pattern_1
;;
pattern_2|pattern_3) # Multiple patterns with |
commands_for_pattern_2_or_3
;;
*) # Default case (catch-all)
default_commands
;;
esac
```
Key points: `case` starts the statement, `in` follows the variable. Patterns end with `)`. Commands are terminated by `;;`. `*` is the default. `esac` closes the statement.
Example: Check car brand and factory location.
Create `car_brand_case.sh`:
```bash
touch car_brand_case.sh
```
Open `car_brand_case.sh` and add:
```bash
#!/usr/bin/env bash
read -p "Enter the name of your car brand: " car
case $car in
Tesla)
echo "${car}'s factory is in the USA."
;;
BMW | Mercedes | Audi | Porsche)
echo "${car}'s factory is in Germany."
;;
Toyota | Mazda | Mitsubishi | Subaru)
echo "${car}'s factory is in Japan."
;;
*)
echo "${car} is an unknown car brand."
;;
esac
```
Save, make executable, and run.
---
### Conclusion
Practice these conditional structures. Modify the examples. Mastering flow control is critical for effective scripting.

View File

@@ -0,0 +1,232 @@
# Loops
Loops are fundamental for automation. Bash provides `for`, `while`, and `until` loops to repeat commands efficiently.
---
### For Loops
The `for` loop iterates through a list of items.
```bash
for var in ${list}
do
your_commands
done
```
Example: Loop through a list of users.
```bash
touch for_users.sh
```
Open `for_users.sh` and add:
```bash
#!/usr/bin/env bash
users="Dev Team Six softwareshinobi troy"
for user in ${users}
do
echo "${user}"
done
```
Save and exit. Make it executable and run:
```bash
chmod +x for_users.sh
./for_users.sh
```
Output:
```
Dev Team Six
softwareshinobi
troy
```
Loop through a range of numbers:
```bash
touch for_numbers.sh
```
Open `for_numbers.sh` and add:
```bash
#!/usr/bin/env bash
for num in {1..10}
do
echo ${num}
done
```
Save, make executable, and run.
### While Loops
A `while` loop continues as long as its condition remains true.
```bash
while [[ your_condition ]]
do
your_commands
done
```
Example: Counter from 1 to 10.
```bash
touch while_counter.sh
```
Open `while_counter.sh` and add:
```bash
#!/usr/bin/env bash
counter=1
while [[ $counter -le 10 ]]
do
echo $counter
((counter++)) # Increment counter
done
```
Save, make executable, run.
Example: Require user input. Loop until a non-empty name is provided.
```bash
touch while_input.sh
```
Open `while_input.sh` and add:
```bash
#!/usr/bin/env bash
read -p "What is your name? " name
while [[ -z "${name}" ]]
do
echo "Name cannot be blank. Please enter a valid name!"
read -p "Enter your name again: " name
done
echo "Hi there ${name}!"
```
Save, make executable, run (test with empty and valid input).
### Until Loops
An `until` loop runs *until* its condition becomes true.
```bash
until [[ your_condition ]]
do
your_commands
done
```
Example: Counter from 1 to 10.
```bash
touch until_loop.sh
```
Open `until_loop.sh` and add:
```bash
#!/usr/bin/env bash
count=1
until [[ $count -gt 10 ]]
do
echo $count
((count++))
done
```
Save, make executable, run.
### Continue and Break
Control loop flow with `continue` (skip current iteration) and `break` (exit loop entirely).
#### `continue`
```bash
touch continue_example.sh
```
Open `continue_example.sh` and add:
```bash
#!/usr/bin/env bash
for i in 1 2 3 4 5
do
if [[ $i -eq 2 ]]; then
echo "Skipping number 2"
continue # Skip to next iteration
fi
echo "i is equal to $i"
done
```
Save, make executable, run.
#### `break`
```bash
touch break_example.sh
```
Open `break_example.sh` and add:
```bash
#!/usr/bin/env bash
num=1
while [[ $num -lt 10 ]]; do
if [[ $num -eq 5 ]]; then
break # Exit loop
fi
((num++))
done
echo "Loop completed. Num stopped at: $num"
```
Save, make executable, run.
For nested loops, `break N` exits `N` levels of loops. `break 2` exits the current and the parent loop.
```bash
touch nested_break_example.sh
```
Open `nested_break_example.sh` and add:
```bash
#!/usr/bin/env bash
for (( a = 1; a < 3; a++ )); do # Outer loop
echo "Outer loop: $a"
for (( b = 1; b < 5; b++ )); do # Inner loop
if [[ $b -gt 2 ]]; then
echo " Breaking inner and outer loop at b=$b"
break 2 # Exits both loops
fi
echo " Inner loop: $b"
done
done
echo "All loops finished."
```
Save, make executable, run.

View File

@@ -0,0 +1,87 @@
# Functions
Functions organize your code for reuse. Here's the structure:
```bash
function_name() {
your_commands
}
```
You can also use the `function` keyword for clarity, though it's optional:
```bash
function function_name() {
your_commands
}
```
Example: A simple 'Hello World!' function.
```bash
touch hello_function.sh
```
Open `hello_function.sh` and add:
```bash
#!/usr/bin/env bash
function hello() {
echo "Hello World Function!"
}
hello # Call the function (no parentheses)
```
Save and exit. Make it executable and run:
```bash
chmod +x hello_function.sh
./hello_function.sh
```
Functions accept arguments just like scripts.
```bash
touch function_args.sh
```
Open `function_args.sh` and add:
```bash
#!/usr/bin/env bash
function greet_team() {
echo "Hello $1!"
}
greet_team "Dev Team Six" # Pass argument when calling
```
Save and exit. Make it executable and run:
```bash
chmod +x function_args.sh
./function_args.sh
```
Document your functions clearly. Include a description, arguments, and expected output/return values.
```bash
#######################################
# Description: Greets a single argument.
# Globals: None
# Arguments:
# $1 - Name/value to greet.
# Outputs:
# Prints a greeting to stdout.
# Returns:
# 0 on success.
#######################################
function greet_example() {
echo "Greeting: $1"
}
```
Functions are key to building organized and reusable Bash scripts. Master them for efficient automation.

View File

@@ -0,0 +1,42 @@
# Debugging
Debugging is vital for efficient Bash scripting.
### Debugging Your Scripts
Troubleshoot your Bash scripts by tracing execution. Use `-x` directly or `set -x` for specific sections.
Run your script with `bash -x` to see every command executed:
```bash
bash -x ./your_script.sh
```
For targeted debugging, use `set -x` where you want to start tracing, and `set +x` to stop.
Create `debug_example.sh`:
```bash
touch debug_example.sh
```
Open `debug_example.sh` and add:
```bash
#!/usr/bin/env bash
echo "Starting script."
set -x # Enable debug mode from here
ls -l
my_variable="test_data"
echo "Variable is: $my_variable"
set +x # Disable debug mode
echo "Debugging finished."
```
Save, make executable, and run:
```bash
chmod +x debug_example.sh
./debug_example.sh
```

View File

@@ -0,0 +1,44 @@
# Debugging
Ensure your Bash scripts run flawlessly. Master debugging to identify issues quickly and build robust code.
### Debugging Your Scripts
Troubleshoot your Bash scripts by tracing execution. Use `-x` directly or `set -x` for specific sections.
Run your script with `bash -x` to see every command executed:
```bash
bash -x ./your_script.sh
```
For targeted debugging, use `set -x` where you want to start tracing, and `set +x` to stop.
Create `debug_example.sh`:
```bash
touch debug_example.sh
```
Open `debug_example.sh` and add:
```bash
#!/usr/bin/env bash
echo "Starting script."
set -x # Enable debug mode from here
ls -l
my_variable="test_data"
echo "Variable is: $my_variable"
set +x # Disable debug mode
echo "Debugging finished."
```
Save, make executable, and run:
```bash
chmod +x debug_example.sh
./debug_example.sh
```
Master these debugging techniques. They are indispensable for building high-quality, dependable Bash scripts.

View File

@@ -0,0 +1,82 @@
# Custom Commands
Optimize repetitive terminal tasks. Custom commands, or aliases, create shortcuts for long or frequently used commands.
### Creating an Alias
Consider a common scenario: checking web server connections with a lengthy `netstat` command:
```bash
netstat -plant | grep '80\|443' | grep -v LISTEN | wc -l
```
Typing this repeatedly is inefficient. Create an alias as a shortcut. For example, let `conn` execute this command.
```bash
alias conn="netstat -plant | grep '80\|443' | grep -v LISTEN | wc -l"
```
Now, simply type `conn`:
```bash
conn
```
You'll get the same output.
Enhance it with an informative message:
```bash
alias conn="echo 'Total connections on port 80 and 443:' ; netstat -plant | grep '80\|443' | grep -v LISTEN | wc -l"
```
Running `conn` will now yield:
```
Total connections on port 80 and 443:
12
```
Note: Aliases created this way are temporary. They disappear when your terminal session ends.
### Making Aliases Permanent
Aliases are session-bound by default. To make them permanent, add them to your shell's profile file. For Bash, this is typically `~/.bashrc`.
Open `~/.bashrc` (or create it if it doesn't exist):
```bash
nano ~/.bashrc
```
Add your alias to the end of the file:
```bash
alias conn="echo 'Total connections on port 80 and 443:' ; netstat -plant | grep '80\|443' | grep -v LISTEN | wc -l"
```
Save and exit.
Apply changes without restarting your terminal:
```bash
source ~/.bashrc
```
Now, your custom command `conn` will be available in all new and sourced terminal sessions.
### Listing Aliases
To view all active aliases in your current shell, simply run:
```bash
alias
```
This helps in troubleshooting command behavior.
### Conclusion
Aliases are powerful tools for optimizing your terminal workflow, offering quick command shortcuts. While full Bash scripts offer more complexity, aliases provide an immediate, user-level solution without requiring root access for installation.
> {notice} This content was inspired by a piece by softwareshinobi on Dev Team Six.

View File

@@ -0,0 +1,142 @@
# Your First Bash Script
Time to build your first Bash script. We'll create a script to monitor server status, including:
* Disk usage
* CPU load
* RAM usage (Memory)
* TCP connections
* Kernel version
Customize as needed.
### Script Setup
First, create your script file, `status.sh`:
```bash
touch status.sh
```
Open `status.sh` with your text editor. Start with the shebang, `#!/usr/bin/env bash`. This tells the system how to execute the script.
Add initial comments for clarity:
```bash
#!/usr/bin/env bash
# Script to report current server status.
```
### Variables
Variables store data. Assign values using `=` (no spaces). Use `$()` for command substitution.
Capture the server's hostname:
```bash
server_name=$(hostname)
```
Echo the variable to see its value:
```bash
echo "${server_name}"
```
### Functions
Functions group commands for reuse. Let's create one for memory usage:
```bash
function memory_check() {
echo ""
echo "Memory usage on ${server_name}: "
free -h
echo ""
}
```
This function prints a message and calls `free -h` for memory details. Call it by name (no parentheses):
```bash
memory_check
```
Before seeing the complete solution, try implementing functions for:
* Disk usage
* CPU load
* TCP connections
* Kernel version
Google commands if needed. There are multiple valid approaches.
### The Complete Script
Here's the full `status.sh` script:
```bash
#!/usr/bin/env bash
##
# Server status script:
# - Memory usage
# - CPU load
# - TCP connections
# - Kernel version
##
server_name=$(hostname)
function memory_check() {
echo ""
echo "Memory usage on ${server_name}: "
free -h
echo ""
}
function cpu_check() {
echo ""
echo "CPU load on ${server_name}: "
echo ""
uptime
echo ""
}
function tcp_check() {
echo ""
echo "TCP connections on ${server_name}: "
echo ""
cat /proc/net/tcp | wc -l
echo ""
}
function kernel_check() {
echo ""
echo "Kernel version on ${server_name}: "
echo ""
uname -r
echo ""
}
function all_checks() {
memory_check
cpu_check
tcp_check
kernel_check
}
all_checks
```
Save `status.sh`, then make it executable and run:
```bash
chmod +x status.sh
./status.sh
```
### Conclusion
Bash scripting combines Linux commands to automate routine tasks, freeing you for more impactful work. This basic script demonstrates the power of automation.
> {notice} This content was inspired by a piece by softwareshinobi on Dev Team Six.

View File

@@ -0,0 +1,265 @@
# Interactive Menu
Build interactive Bash menus. This guide shows you how to create a menu where users choose which actions to run, leveraging previously defined functions for server status checks:
* Memory usage
* CPU load
* TCP connections
* Kernel version
Here's the base script containing these functions:
```bash
#!/usr/bin/env bash
##
# Server status script:
# - Memory usage
# - CPU load
# - Number of TCP connections
# - Kernel version
##
server_name=$(hostname)
function memory_check() {
echo ""
echo "Memory usage on ${server_name}: "
free -h
echo ""
}
function cpu_check() {
echo ""
echo "CPU load on ${server_name}: "
echo ""
uptime
echo ""
}
function tcp_check() {
echo ""
echo "TCP connections on ${server_name}: "
echo ""
cat /proc/net/tcp | wc -l
echo ""
}
function kernel_check() {
echo ""
echo "Kernel version on ${server_name}: "
echo ""
uname -r
echo ""
}
function all_checks() {
memory_check
cpu_check
tcp_check
kernel_check
}
```
We'll now integrate this with a menu, allowing users to select a function to execute.
---
### Add Color for Readability
Enhance your menu's readability with simple color functions. Add these variables and functions to your script:
```bash
##
# Color Variables
##
green='\e[32m'
blue='\e[34m'
red='\e[31m'
clear='\e[0m'
##
# Color Functions
##
ColorGreen(){
echo -ne $green$1$clear
}
ColorBlue(){
echo -ne $blue$1$clear
}
ColorRed(){
echo -ne $red$1$clear
}
```
Use them like: `$(ColorBlue 'Your text')`.
---
### Build the Interactive Menu
Create a `menu` function containing the display logic, user input, and a `case` statement for selection.
```bash
menu(){
echo -ne "
My Server Status Menu
$(ColorGreen '1)') Memory usage
$(ColorGreen '2)') CPU load
$(ColorGreen '3)') TCP connections
$(ColorGreen '4)') Kernel version
$(ColorGreen '5)') Check All
$(ColorGreen '0)') Exit
$(ColorBlue 'Choose an option:') "
read -r a
case $a in
1) memory_check ; menu ;;
2) cpu_check ; menu ;;
3) tcp_check ; menu ;;
4) kernel_check ; menu ;;
5) all_checks ; menu ;;
0) exit 0 ;;
*) echo -e $(ColorRed 'Invalid option.') ; menu ;;
esac
}
```
Here's how it works:
* The `echo -ne` block prints the menu options, applying colors.
* `read -r a` captures user input into variable `a`.
* The `case` statement executes the corresponding function. After each function, `menu` is called again to display the menu for another choice, creating a loop. `exit 0` handles the exit option.
Finally, call the `menu` function at the end of your script to start the interaction:
```bash
menu
```
---
### Complete Script and Testing
Here's the entire script, `menu.sh`, combining all components:
```bash
#!/usr/bin/env bash
##
# BASH menu script that checks:
# - Memory usage
# - CPU load
# - Number of TCP connections
# - Kernel version
##
server_name=$(hostname)
function memory_check() {
echo ""
echo "Memory usage on ${server_name}: "
free -h
echo ""
}
function cpu_check() {
echo ""
echo "CPU load on ${server_name}: "
echo ""
uptime
echo ""
}
function tcp_check() {
echo ""
echo "TCP connections on ${server_name}: "
echo ""
cat /proc/net/tcp | wc -l
echo ""
}
function kernel_check() {
echo ""
echo "Kernel version on ${server_name}: "
echo ""
uname -r
echo ""
}
function all_checks() {
memory_check
cpu_check
tcp_check
kernel_check
}
##
# Color Variables
##
green='\e[32m'
blue='\e[34m'
red='\e[31m'
clear='\e[0m'
##
# Color Functions
##
ColorGreen(){
echo -ne $green$1$clear
}
ColorBlue(){
echo -ne $blue$1$clear
}
ColorRed(){
echo -ne $red$1$clear
}
menu(){
echo -ne "
My Server Status Menu
$(ColorGreen '1)') Memory usage
$(ColorGreen '2)') CPU load
$(ColorGreen '3)') TCP connections
$(ColorGreen '4)') Kernel version
$(ColorGreen '5)') Check All
$(ColorGreen '0)') Exit
$(ColorBlue 'Choose an option:') "
read -r a
case $a in
1) memory_check ; menu ;;
2) cpu_check ; menu ;;
3) tcp_check ; menu ;;
4) kernel_check ; menu ;;
5) all_checks ; menu ;;
0) exit 0 ;;
*) echo -e $(ColorRed 'Invalid option.') ; menu ;;
esac
}
# Call the menu function
menu
```
Save this code as `menu.sh`:
```bash
touch menu.sh
```
Open `menu.sh` and paste the script. Save and close. Then, make it executable and run:
```bash
chmod +x menu.sh
./menu.sh
```
You'll see the colored menu, prompting for input. Select an option (e.g., `1` for memory check), and the corresponding information will display before the menu reappears, ready for another choice.
---
### Conclusion
You've built an interactive Bash menu, allowing users to effortlessly navigate script functionalities. This enhances user experience for your automation tools.
> {notice} This content was inspired by a piece by softwareshinobi on Dev Team Six.

View File

@@ -0,0 +1,113 @@
# Running On Multiple Servers
Automate script execution across multiple remote servers. Instead of manual copying and logging in, learn to run Bash scripts on many machines with a single command.
### Prerequisites
You'll need a few remote Linux servers with **SSH access**. Gather their **IP addresses** or **hostnames** and list them in a file named `servers.txt`, one per line.
Create `servers.txt`:
```bash
touch servers.txt
```
Open `servers.txt` and add your server details:
```
your_server_ip_1
your_server_ip_2
your_server_ip_3
```
---
### The Script for Remote Execution
We'll use a simple Bash script that performs basic server checks: memory, CPU, TCP connections, and kernel version. Create a file named `remote_check.sh` and add the following content:
```bash
touch remote_check.sh
```
Open `remote_check.sh` and add:
```bash
#!/usr/bin/env bash
##
# Server status script:
# - Memory usage
# - CPU load
# - Number of TCP connections
# - Kernel version
##
server_name=$(hostname)
function memory_check() {
echo "#######"
echo "The current memory usage on ${server_name} is: "
free -h
echo "#######"
}
function cpu_check() {
echo "#######"
echo "The current CPU load on ${server_name} is: "
echo ""
uptime
echo "#######"
}
function tcp_check() {
echo "#######"
echo "Total TCP connections on ${server_name}: "
echo ""
cat /proc/net/tcp | wc -l
echo "#######"
}
function kernel_check() {
echo "#######"
echo "The exact Kernel version on ${server_name} is: "
echo ""
uname -r
echo "#######"
}
function all_checks() {
memory_check
cpu_check
tcp_check
kernel_check
}
all_checks
```
---
### Execute on Remote Servers
With `remote_check.sh` and `servers.txt` ready, run the following single command. This loop iterates through each server, using **SSH** to execute the script without local file transfer or manual logins.
```bash
for server in $(cat servers.txt); do ssh your_user@"${server}" 'bash -s' < ./remote_check.sh; done
```
**Breakdown:**
* `for server in $(cat servers.txt)`: Reads each IP/hostname from `servers.txt` into the `server` variable.
* `ssh your_user@"${server}"`: Connects to the remote server via SSH as `your_user`.
* `'bash -s'`: Executes a Bash shell on the remote server, reading commands from standard input.
* `< ./remote_check.sh`: Redirects the local `remote_check.sh` script's content to the remote Bash shell's standard input.
Each server will then execute the script, printing its status checks directly to your local terminal.
---
### Conclusion
This method efficiently executes Bash scripts across multiple remote servers. It avoids manual file transfers and individual logins, proving scalable for more complex scripts and larger environments. For extensive, state-managed automation, dedicated tools are often recommended.
> {notice} This content was inspired by a piece by softwareshinobi on Dev Team Six.

View File

@@ -0,0 +1,134 @@
# Json Data
`jq` is your lightweight, flexible command-line JSON processor. It's built in portable C with zero runtime dependencies, making it simple to install and powerful for parsing JSON in Bash.
-----
### Demo Setup: QuizAPI
This demo uses the [QuizAPI](https://quizapi.io/) to fetch JSON data. Obtain a free **API key** from their [client area](https://quizapi.io/clientarea/settings/token) to follow along.
-----
### Installing `jq`
`jq` is easily installed via your system's package manager or direct download.
* **Ubuntu/Debian:** `sudo apt-get install jq`
* **Red Hat/Fedora:** `sudo dnf install jq`
* **Arch Linux:** `sudo pacman -S jq`
For other systems, refer to the [official `jq` download page](https://www.google.com/search?q=%5Bhttps://stedolan.github.io/jq/download/%5D\(https://stedolan.github.io/jq/download/\)). Verify your installation:
```bash
jq --version
```
-----
### Basic JSON Parsing with `jq`
Once `jq` is installed and you have your QuizAPI key, you can start processing JSON.
First, set your API key:
```bash
API_KEY=YOUR_API_KEY_HERE # Replace with your actual key
```
Fetch questions using `curl`:
```bash
curl "https://quizapi.io/api/v1/questions?apiKey=${API_KEY}&limit=10"
```
The raw output is hard to read. Pipe it to `jq` for beautifully formatted and colored JSON:
```bash
curl "https://quizapi.io/api/v1/questions?apiKey=${API_KEY}&limit=10" | jq
```
This command makes the JSON output structured and easy to inspect.
-----
### Extracting Specific Elements
To get only the first element from a JSON array, use `.[0]`:
```bash
curl "https://quizapi.io/api/v1/questions?apiKey=${API_KEY}&limit=10" | jq '.[0]'
```
This will output only the first JSON object in the array.
-----
### Fetching Key Values Across an Array
To extract the value of a specific key (e.g., `question`) from every object in a JSON array, use `.[].key`:
```bash
curl "https://quizapi.io/api/v1/questions?apiKey=${API_KEY}&limit=10" | jq '.[].question'
```
This will return a list of all questions from the API response.
-----
### Integrating `jq` into a Bash Script
Let's create a script to fetch a question and its answers, then display them. We'll use `jq` to parse specific fields and assign them to Bash variables.
Create `quiz_script.sh`:
```bash
touch quiz_script.sh
```
Open `quiz_script.sh` and add (remember to replace `YOUR_API_KEY_HERE`):
```bash
#!/usr/bin/env bash
# Your QuizAPI Key (replace YOUR_API_KEY_HERE with your actual key)
API_KEY="YOUR_API_KEY_HERE"
# Make an API call and get the first question object
# Using -s for silent mode to suppress curl's progress meter
QUIZ_DATA=$(curl -s "https://quizapi.io/api/v1/questions?apiKey=${API_KEY}&limit=1" 2>/dev/null)
# Extract specific values using jq with raw output (-r) for Bash variables
question=$(echo "${QUIZ_DATA}" | jq -r '.[0].question')
answer_a=$(echo "${QUIZ_DATA}" | jq -r '.[0].answers.answer_a')
answer_b=$(echo "${QUIZ_DATA}" | jq -r '.[0].answers.answer_b')
answer_c=$(echo "${QUIZ_DATA}" | jq -r '.[0].answers.answer_c')
answer_d=$(echo "${QUIZ_DATA}" | jq -r '.[0].answers.answer_d')
# Output the question and answers
echo "
Question: ${question}
A) ${answer_a}
B) ${answer_b}
C) ${answer_c}
D) ${answer_d}
"
```
Save, make executable, and run:
```bash
chmod +x quiz_script.sh
./quiz_script.sh
```
The script will print a random question and its corresponding answers. For more advanced, interactive Bash quizzes, explore community projects that build upon these `jq` principles.
-----
### Conclusion
`jq` empowers you to process **JSON** directly within your Bash terminal, facilitating seamless interaction with **REST APIs**. For deeper dives, consult the [official `jq` manual](https://www.google.com/search?q=%5Bhttps://stedolan.github.io/jq/manual/%5D\(https://stedolan.github.io/jq/manual/\)) and the [QuizAPI documentation](https://quizapi.io/docs/1.0/overview).
> {notice} This content was inspired by a piece by softwareshinobi on Dev Team Six.

View File

@@ -0,0 +1,217 @@
# Redirection
Master Bash redirection and pipes. These essential Linux features are critical for efficient system administration. Every command handles input, output, and errors through **File Descriptors (FDs)**:
* **STDIN** (0): Standard Input receives data.
* **STDOUT** (1): Standard Output sends regular data.
* **STDERR** (2): Standard Error sends error messages.
---
### Pipes vs. Redirection
Both manage data streams, but with a key difference:
* **Redirection** routes a command's input/output to or from a **file**.
* **Pipes** (`|`) connect the **output of one command directly to the input of another command**.
---
### STDIN (Standard Input)
Commands often expect input. By default, this is your keyboard, but you can redirect it from other sources.
**Redirecting from a file (`<`)**:
Use `<` to feed a file's content as input to a command. Create `input.txt`:
```bash
touch input.txt
```
Open `input.txt` and add:
```
Line 1
Line 2
```
Save `input.txt`.
Then run:
```bash
cat < input.txt
```
This prints `input.txt` content, similar to `cat input.txt`.
**Here-Documents (`<< DELIMITER`)**:
For multi-line input directly in your script or terminal, use a here-document with a custom delimiter (e.g., `EOF`).
```bash
cat << EOF
Hello World!
How are you?
EOF
```
This will print:
```
Hello World!
How are you?
```
Similarly, with `wc -l` to count lines:
```bash
wc -l << EOF
Hello World!
How are you?
EOF
```
Output:
```
2
```
---
### STDOUT (Standard Output)
Regular command output typically goes to your terminal. Redirect it to a file.
**Overwrite (`>`)**:
Use `>` to send output to a file. If the file exists, its content is overwritten. Create `file.txt` (or ensure it's empty):
```bash
echo "Hello World!" > file.txt
cat file.txt # Output: Hello World!
```
Running again overwrites:
```bash
echo "How are you?" > file.txt
cat file.txt # Output: How are you? (Previous content is gone)
```
**Append (`>>`)**:
Use `>>` to add output to the end of a file without overwriting existing content.
```bash
echo "Hello World!" > file.txt # Start fresh
echo "How are you?" >> file.txt
cat file.txt
```
Output:
```
Hello World!
How are you?
```
You can also explicitly specify the STDOUT file descriptor (1): `echo "Hello" 1> file.txt`.
---
### STDERR (Standard Error)
Error messages, distinct from standard output, are sent to **STDERR**. Redirect them using file descriptor 2.
**Redirecting Errors (`2>`)**:
Use `2>` to redirect error messages. For example, `ls --invalid-flag` generates an error.
```bash
ls --invalid-flag 2> error.txt
cat error.txt # Contains the error message
```
Use `2>>` to append error messages to a file.
**Discarding Errors (`2> /dev/null`)**:
Send error output to `/dev/null` to completely suppress it. `/dev/null` is a special 'black hole' device that discards all data written to it.
```bash
ls --invalid-flag 2> /dev/null # Error message is hidden
```
**Redirecting Both STDOUT and STDERR**:
You can manage both streams simultaneously.
To separate regular output and errors into different files:
```bash
# Assuming 'install_package.sh' generates both output and errors
./install_package.sh > output.txt 2> error.txt
```
To send both to the same file (concise syntax):
```bash
./install_package.sh > combined_output.txt 2>&1
```
The `2>&1` redirects file descriptor 2 (STDERR) to the same location as file descriptor 1 (STDOUT), which is `combined_output.txt`. Alternatively, an even shorter Bash 4+ syntax: `&> combined_output.txt`.
---
### Piping (`|`)
Pipes connect the standard output of one command directly to the standard input of another, creating powerful command chains.
**Basic Example:** Find `.txt` files in a directory listing.
```bash
ls | grep ".txt"
```
This sends `ls`'s output to `grep` for filtering.
**Chaining Commands:** Analyze file ownership in a directory.
```bash
ls -l /projects/bash_scripts | tail -n +2 | sed 's/\s\s*/ /g' | cut -d ' ' -f 3 | sort | uniq -c
```
This sequence lists files, removes the header, cleans spacing, extracts owner names, sorts them, and counts unique occurrences.
---
### Here-Documents (`<< DELIMITER`)
Here-documents (`<<`) provide multi-line input directly within your script or terminal, ideal for commands that read from STDIN without needing a separate temporary file.
Specify a custom delimiter (e.g., `EOF`):
```bash
cat << END_MESSAGE
This text will be passed as input to cat.
It spans multiple lines.
END_MESSAGE
```
Output:
```
This text will be passed as input to cat.
It spans multiple lines.
```
You can also pipe the output of a here-document to another command:
```bash
wc -l << MESSAGE_LINES
Line one.
Line two.
Line three.
MESSAGE_LINES
```
Output: `3` (counts the lines). Variables are expanded within here-documents.
---
### Here-Strings (`<<<`)
For piping a single string into a command's STDIN, use a here-string (`<<<`). This is cleaner than a here-document for single lines.
```bash
wc -w <<<"This is a sample string for word count."
```
Output: `7` (counts words).
Variables are also supported in here-strings.
---
### Summary of Redirection and Piping Operators
| **Operator** | **Description** |
| :--- | :--- |
| `>` | Redirect STDOUT to a file, overwriting existing content. |
| `>>` | Redirect STDOUT to a file, appending to existing content. |
| `<` | Redirect STDIN from a file. |
| `2>` | Redirect STDERR to a file, overwriting existing content. |
| `|` | Pipe STDOUT of one command to STDIN of another. |
| `<<` | Here-document: Provide multi-line STDIN from the script. |
| `<<<` | Here-string: Provide single-line STDIN from the command line. |