Frequently and useful Bash scripts

In this post or cheat sheet, we are going to code some really useful scripts for our daily use.
Last Updated: 03/august/22-


The importance of shebang (#!)

We can see in the first line of a script file, after the shebang, a location. This tell to our system what type of language we are using and where to find it. We can also set our script to run with perl or python, for example. But why there are different starts to specify an interpreter? We can find some script starting with:

  • #!/bin/bash
  • #!/usr/bin/bash
  • #!/usr/local/bin/bash
  • #!/usr/bin/env bash
  • #!/bin/csh

When we use #!/bin/bash, #!/usr/bin/bash, #!/usr/local/bin/bash or others, we are defining the absolute path of the language, this could change in different system. We can check where is ours by typing:

$ which bash
/usr/bin/bash 

Now when we use:

#!/usr/bin/env bash

env” could be considered “portable” in that the path to bash is not relevant because it is specified in the environment. In this way, a script author could make his script easier to run on many systems.

This could be a situational parameter because env it will use whatever bash executable appears first in the user’s $PATH. This means that the script could behave differently depending on who runs it. Using another language like python, could be a problem for users with different versions of it.

By specifying #!/usr/bin/python you specify exactly which interpreter will be used to run the script on a particular system.

Another potential problem is that the #!/usr/bin/env trick doesn’t let you pass arguments to the interpreter (other than the name of the script, which is passed implicitly). This usually isn’t an issue, but it can be. When I’m testing a new script, I personally use:

#!/bin/bash -ex

The “e” it would make the script stop if a line in the script fails, and “x” it shows you every line of the script being executed.


How can I execute a script from anywhere?

To make a script able to execute from anywhere, we first need to understand how the scripts are launched. As I say before, the script read what language is defined in the user $PATH to execute the script. So if we add the location of the script to the $PATH, the script can be executed from anywhere. To do this we all need to type:

$ PATH:$PATH:"script path"

$ PATH=$PATH:/home/mati/myScriptFolder 

Now if we check the variable $PATH:

$ $PATH
-bash: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/mati/myScriptFolder

We are going to see our new folder with script at the final of $PATH. Now we can try executing our script simple calling it from anywhere.

Note: This is a temporal solution, if you exit your session, when you enter again you have to do this again.

Add PATH permanently

If you want to add this path permanently, you to need to edit ~/.bashrc file:

$ nano ~/.bashrc

# Go to the bottom, and add the following code, replacing "$HOME/scripts"

export PATH="$PATH:$HOME/scripts"

Type “echo $PATH” to check if everything it’s okay.


Simple scripts

Remember to give execute permission when you create a new script:

$ touch newScript.sh
$ chmod u+x newScript.sh

Full update and upgrade of your system, with “-y” argument you select “Yes” to the size of the download, you have to be careful. Also, you need to run this script as superuser:

#!/bin/bash

# This is for Debian base servers

sudo apt update -y && apt upgrade -y

SSH connection (I recommend to use ssh keys, but if you don’t want to use sshkeys…):

#!/bin/bash

# ssh "user"@"domain or IP" -p "port"

ssh [email protected] -p 2022

Find a file:

#!/bin/bash

echo
echo "Name of the file you need "
read FILE
echo "Write the folder to search "
read FOLDER

FILE="*$FILE*"

set -x
find "$FOLDER" -name "$FILE"

Get information about a folder/files size:

#!/bin/bash
# How much storage is used and in every folder of a path

echo ---------------------------
echo Enter the path to measure

read FOLDER

sudo du -h -x -d1 $FOLDER

Get information about a file:

#!/bin/bash

echo Type file/directory name (using the absolute path)
read FILE

if [ -e "$FILE" ]; then
	if [ -f "$FILE" ]; then
		echo "$FILE is a regular file."
	fi
	if [ -d "$FILE" ]; then
		echo "$FILE is a directory."
	fi
	if [ -r "$FILE" ]; then
		echo "$FILE is readable."
	fi
	if [ -w "$FILE" ]; then
		echo "$FILE is writable."
	fi
	if [ -x "$FILE" ]; then
		echo "$FILE is executable/searchable."
	fi
else
	echo "$FILE does not exist"
	exit 1
fi
exit

Generate a random password with a predefined length:

#!/bin/bash

echo This is a simple password generator
echo Enter the length of the password: 
read PASS_LENGHT

for p in $(seq 1 5);
do
	openssl rand -base64 48 | cut -c1-$PASS_LENGTH

done

Encrypt/Decrypt a file/folder:

#!/bin/bash

echo "Simple file encrypter/decrypter"
echo "Choose Encrypt or Decrypt"

choice="Encrypt Decrypt"

select option in $choice; do
        if [ $REPLY = 1 ];
then
        echo "Please enter the filename you want to encrypt"
        read file;
        gpg -c $file
        echo "The file has been encrypted"
else
        echo  "Please enter the filename you want to decrypt"
        read file2;
        gpg -d $file2
        echo "The file has been decrypted"
fi

done

Check internet speed (you need to have python installed):

#!/bin/bash

if ! python3 -v <python> &> /dev/null
then
    sudo apt install python3 -y
fi

curl -s https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py | python -

I love this one, check the weather using your current location:

#!/bin/bash


program=Weather
version=1.1
year=2022
developer=computer-geek64

case $1 in
-h | --help)
	echo "$program $version"
	echo "Copyright $year $developer. All rights reserved."
	echo
	echo "Usage: weather [options]"
	echo "Option          Long Option             Description"
	echo "-h              --help                  Show the help screen"
	echo "-l [location]   --location [location]   Specifies the location"
	;;
-l | --location)
	curl https://wttr.in/$2
	;;
*)
	curl https://wttr.in
	;;
esac
weather.sh in action

More complex ones

Check status code from a website:

#!/bin/bash -e

## You need to add your sites to list.txt to be checked 
## Status code for http: 200= OK. 400= Bad Request. 404= Not found 
## You can check all the status codes here: 
## https://developer.mozilla.org/es/docs/Web/HTTP/Status 

while read line; do
   response=$(curl --write-out "%{http_code}\n)" --silent --output /dev/null "$line")
   echo $line: $response
done < list.txt

Set up Git:

#!/bin/bash -ex

echo
read -p "Write your git username: " USER
DEFAULT_EMAIL="[email protected]"
read -p "Write your git email [Press enter to accept the private email $DEFAULT_EMAIL]: " EMAIL
EMAIL="${EMAIL:-${DEFAULT_EMAIL}}"

echo "Configuring global user name and email..."
git config --global user.name "$USER"
git config --global user.email "$EMAIL"

echo "Configuring global aliases..."
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.sub "submodule update --remote --merge"
git config --global core.editor "vim"
git config --global credential.helper 'cache --timeout=36000'

read -r -p "Do you want to add ssh credentials for git? [y/n] " RESP
RESP=${RESP,,}    # tolower (only works with /bin/bash)
if [[ $RESP =~ ^(yes|y)$ ]]
then
    echo "Configuring git ssh access..."
    ssh-keygen -t ed25519 -C "$EMAIL"
    echo "This is your public key. To activate it in github, got to settings, SHH and GPG keys, New SSH key, and enter the following key:"
    cat ~/.ssh/id_ed25519.pub
    echo ""
    echo "To work with the ssh key, you have to clone all your repos with ssh instead of https. For example, for this repo you will have to use the url: [email protected]:miguelgfierro/scripts.git"
fi

if [ "$(uname)" == "Darwin" ]; then # Mac OS X platform  
	echo "Setting autocompletion"
	AUTOCOMPLETION_URL="https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash"
	AUTOCOMPLETION_PATH=/opt/local/etc/bash_completion.d
	AUTOCOMPLETION_SCRIPT=git-completion.bash 
	sudo mkdir -p $AUTOCOMPLETION_PATH
	sudo curl  -o $AUTOCOMPLETION_PATH/$AUTOCOMPLETION_SCRIPT $AUTOCOMPLETION_URL
	source $AUTOCOMPLETION_PATH/$AUTOCOMPLETION_SCRIPT
	echo "source $AUTOCOMPLETION_PATH/$AUTOCOMPLETION_SCRIPT" >> ~/.bash_profile
fi
echo ""
echo "git configured"

Create a new user on MySQL:

#!/bin/bash -e

# Create a new user and database on your local mysql server

set -e

usage()
{
cat << EOF
Usage: $0 --user=mysql_user --password=mysql_password
Create a new user and database on your local mysql server
OPTIONS:
  -u, --user=user            MySQL user
  -p, --password=password    MySQL password
  -r, --root-password        MySQL root password
  -h, --help                 Prints this message
EOF
}

verbose=false

#Parse arguments
if [ "$#" -eq 0 ] ; then
    usage
    exit 2
fi
PARAMS=`getopt -n $0 -o u:p:r:h:v --long user:,password:,root-password:,help,verbose -- "$@"`
eval set -- "$PARAMS"
while true ; do
    case "$1" in
        -u|--user) mysql_user=$2; shift 2 ;;
        -p|--password) mysql_password=$2 ; shift 2 ;;
        -r|--root-password) root_password=$2 ; shift 2 ;;
        -h|--help) usage ; exit 1 ;;
        -v|--verbose) verbose=true ; shift ;;
        --) shift ; break ;;
        *) usage ; exit 2 ;;
    esac
done

# Error checking

error_state=0;

if [ -z "$mysql_user" ] ; then
    echo "You MUST specify MySQL user !"
    error_state=1
fi

if [ -z "$mysql_password" ] ; then
    echo "You MUST specify MySQL password !"
    error_state=1
fi

if [ "$error_state" = 1 ] ; then
    echo "There are errors in your arguments, exiting."
    exit 2
fi

if [ $verbose == true ]; then
    echo "Creating user \"$mysql_user\" with associated database"
    echo "Password: \"$mysql_password\""
    echo "Root password: \"$root_password\""
fi

cd /tmp
cat > create_user.sql << EOF
 GRANT USAGE ON *.* TO '$mysql_user'@'localhost';
 DROP USER '$mysql_user'@'localhost';
 DROP DATABASE IF EXISTS $mysql_user ;
 CREATE USER '$mysql_user'@'localhost' IDENTIFIED BY '$mysql_password';
 GRANT USAGE ON * . * TO '$mysql_user'@'localhost' IDENTIFIED BY '$mysql_password' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0   MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;
 CREATE DATABASE IF NOT EXISTS $mysql_user character set utf8;
 GRANT ALL PRIVILEGES ON $mysql_user . * TO '$mysql_user'@'localhost';
EOF
mysql -uroot -p"$root_password" < create_user.sql
rm create_user.sql

Backup a database:

#!/bin/bash -ex

export PATH=/bin:/usr/bin:/usr/local/bin
TODAY=`date +"%d%b%Y"`

# Update below values

DB_BACKUP_PATH='/backup/dbbackup'
MYSQL_HOST='localhost'
MYSQL_PORT='3306'
MYSQL_USER='root'
MYSQL_PASSWORD='mysecret'
DATABASE_NAME='mydb'
# Number of days to keep local backup copy
BACKUP_RETAIN_DAYS=30 

mkdir -p ${DB_BACKUP_PATH}/${TODAY}
echo "Backup started for database - ${DATABASE_NAME}"

mysqldump -h ${MYSQL_HOST} \
-P ${MYSQL_PORT} \
-u ${MYSQL_USER} \
-p${MYSQL_PASSWORD} \
${DATABASE_NAME} | gzip &gt; ${DB_BACKUP_PATH}/${TODAY}/${DATABASE_NAME}-${TODAY}.sql.gz

if [ $? -eq 0 ]; then
echo "Database backup successfully completed"
else
echo "Error found during backup"
exit 1
fi

## Remove backups older than {BACKUP_RETAIN_DAYS} days

DBDELDATE=`date +"%d%b%Y" --date="${BACKUP_RETAIN_DAYS} days ago"`

if [ ! -z ${DB_BACKUP_PATH} ]; then
cd ${DB_BACKUP_PATH}
if [ ! -z ${DBDELDATE} ] &amp;&amp; [ -d ${DBDELDATE} ]; then
rm -rf ${DBDELDATE}
fi
fi

Hope you find some useful. I’m going to be updating this post

2 thoughts on “Frequently and useful Bash scripts”

  1. Pingback: Networking with Linux: commands, services and more – the admin notes

Leave a Comment

Your email address will not be published. Required fields are marked *