Execute a command whenever a file changes

You can do this with inotifywait utility from inotify-tools package

while true ; do
  inotifywait -e delete_self "/tmp/fileToMonitor.txt" \
    && cp new_file "/tmp/fileToMonitor.txt"
done
[ "$UID" -eq 0 ] || exec sudo "$0" "$@"

while true ; do
  inotifywait -e modify "/etc/resolv.conf" && ./dns.sh
done

References
https://superuser.com/questions/939600/how-to-get-notified-when-a-specific-file-is-deleted-in-linux
https://superuser.com/questions/181517/how-to-execute-a-command-whenever-a-file-changes
http://man7.org/linux/man-pages/man1/inotifywait.1.html#EVENTS

Command Substitution in bash

Text between backticks is executed and replaced by the output of the command (minus the trailing newline characters, and beware that shell behaviors vary when there are NUL characters in the output). That is called command substitution because it is substituted with the output of the command.

A=`cat /etc/p2ass2wd2 | head -n1`
echo "$A"
A=$(cat /etc/p2ass2wd2 | head -n1)
echo "$A"

References
https://unix.stackexchange.com/questions/48392/understanding-backtick
https://unix.stackexchange.com/questions/147420/what-is-in-a-command

Get IP Address using bash

Displaying private IP addresses

ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1  -d'/'

address=$(ip addr show wlp3s0 | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1  -d'/')

Displaying the public IP address

If you want to know the public IP address of a Linux server, you can send an HTTP request to one of the following web servers.

  • http://ifconfig.me
  • http://www.icanhazip.com
  • http://ipecho.net/plain
  • http://indent.me
  • http://bot.whatismyipaddress.com
  • https://diagnostic.opendns.com/myip
  • http://checkip.amazonaws.com
curl http://checkip.amazonaws.com
wget -qO- http://checkip.amazonaws.com

References
https://unix.stackexchange.com/questions/119269/how-to-get-ip-address-using-shell-script
https://www.linuxtrainingacademy.com/determine-public-ip-address-command-line-curl/

Save terminal output to a file

          || visible in terminal ||   visible in file   || existing
  Syntax  ||  StdOut  |  StdErr  ||  StdOut  |  StdErr  ||   file   
==========++==========+==========++==========+==========++===========
    >     ||    no    |   yes    ||   yes    |    no    || overwrite
    >>    ||    no    |   yes    ||   yes    |    no    ||  append
          ||          |          ||          |          ||
   2>     ||   yes    |    no    ||    no    |   yes    || overwrite
   2>>    ||   yes    |    no    ||    no    |   yes    ||  append
          ||          |          ||          |          ||
   &>     ||    no    |    no    ||   yes    |   yes    || overwrite
   &>>    ||    no    |    no    ||   yes    |   yes    ||  append
          ||          |          ||          |          ||
 | tee    ||   yes    |   yes    ||   yes    |    no    || overwrite
 | tee -a ||   yes    |   yes    ||   yes    |    no    ||  append
          ||          |          ||          |          ||
 n.e. (*) ||   yes    |   yes    ||    no    |   yes    || overwrite
 n.e. (*) ||   yes    |   yes    ||    no    |   yes    ||  append
          ||          |          ||          |          ||
|& tee    ||   yes    |   yes    ||   yes    |   yes    || overwrite
|& tee -a ||   yes    |   yes    ||   yes    |   yes    ||  append
  • command > output.txt

    The standard output stream will be redirected to the file only, it will not be visible in the terminal. If the file already exists, it gets overwritten.

  • command >> output.txt

    The standard output stream will be redirected to the file only, it will not be visible in the terminal. If the file already exists, the new data will get appended to the end of the file.

  • command 2> output.txt

    The standard error stream will be redirected to the file only, it will not be visible in the terminal. If the file already exists, it gets overwritten.

  • command 2>> output.txt

    The standard error stream will be redirected to the file only, it will not be visible in the terminal. If the file already exists, the new data will get appended to the end of the file.

  • command &> output.txt

    Both the standard output and standard error stream will be redirected to the file only, nothing will be visible in the terminal. If the file already exists, it gets overwritten.

  • command &>> output.txt

    Both the standard output and standard error stream will be redirected to the file only, nothing will be visible in the terminal. If the file already exists, the new data will get appended to the end of the file..

  • command | tee output.txt

    The standard output stream will be copied to the file, it will still be visible in the terminal. If the file already exists, it gets overwritten.

  • command | tee -a output.txt

    The standard output stream will be copied to the file, it will still be visible in the terminal. If the file already exists, the new data will get appended to the end of the file.

  • command |& tee output.txt

    Both the standard output and standard error streams will be copied to the file while still being visible in the terminal. If the file already exists, it gets overwritten.

  • command |& tee -a output.txt

    Both the standard output and standard error streams will be copied to the file while still being visible in the terminal. If the file already exists, the new data will get appended to the end of the file.

References
https://askubuntu.com/questions/420981/how-do-i-save-terminal-output-to-a-file

Taking Command Line Arguments in Bash

Pass arguments through to another program

#!/bin/bash
# print_args.sh
echo "You provided the arguments:" "$@"

# You could pass all arguments to another program like this
# myProgram "$@"

Get the number of arguments passed

#!/bin/bash
echo "You provided $# arguments"

Accessing a specific argument by index

#!/bin/bash
echo "Arg 0: $0"
echo "Arg 1: $1"
echo "Arg 2: $2"

Argument 0 is the name of the script being invoked itself.

Iterating through each argument

#!/bin/bash
for arg in "$@"
do
    echo "$arg"
done

Check arguments for specific value

#!/bin/bash
for arg in "$@"
do
    if [ "$arg" == "--help" ] || [ "$arg" == "-h" ]
    then
        echo "Help argument detected."
    fi
done

References
https://www.devdungeon.com/content/taking-command-line-arguments-bash

Best way to test if a systemd service is running in bash script

systemctl is-active application.service
systemctl is-enabled application.service
systemctl is-active --quiet service

will exit with status zero if service is active, non-zero otherwise, making it ideal for scripts:

systemctl is-active --quiet service && echo Service is running

References
https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units
https://unix.stackexchange.com/questions/396630/the-proper-way-to-test-if-a-service-is-running-in-a-script

Check if a File or Directory Exists in Bash

Check if File Exist

FILE=/etc/resolv.conf
if test -f "$FILE"; then
    echo "$FILE exist"
fi
FILE=/etc/resolv.conf
if [ -f "$FILE" ]; then
    echo "$FILE exist"
fi
FILE=/etc/resolv.conf
if [[ -f "$FILE" ]]; then
    echo "$FILE exist"
fi

Check if Directory Exist

FILE=/etc/docker
if [ -d "$FILE" ]; then
    echo "$FILE is a directory"
fi

Check if File does Not Exist

FILE=/etc/docker
if [ ! -f "$FILE" ]; then
    echo "$FILE does not exist"
fi

Check if Multiple Files Exist

FILE=/etc/docker
if [ -f /etc/resolv.conf -a -f /etc/hosts ]; then
    echo "$FILE is a directory"
fi
FILE=/etc/docker
if [ -f /etc/resolv.conf && -f /etc/hosts ]; then
    echo "$FILE is a directory"
fi

File test operators

  • -f FILE – True if the FILE exists and is a regular file (not a directory or device).
  • -G FILE – True if the FILE exists and has the same group as the user running the command.
  • -h FILE – True if the FILE exists and is a symbolic link.
  • -g FILE – True if the FILE exists and has set-group-id (sgid) flag set.
  • -k FILE – True if the FILE exists and has a sticky bit flag set.
  • -L FILE – True if the FILE exists and is a symbolic link.
  • -O FILE – True if the FILE exists and is owned by the user running the command.
  • -p FILE – True if the FILE exists and is a pipe.
  • -r FILE – True if the FILE exists and is readable.
  • -S FILE – True if the FILE exists and is socket.
  • -s FILE – True if the FILE exists and has nonzero size.
  • -u FILE – True if the exists and set-user-id (suid) flag is set.
  • -w FILE – True if the FILE exists and is writable.
  • -x FILE – True if the FILE exists and is executable.

References
https://linuxize.com/post/bash-check-if-file-exists/