Compile Bash Script into Binary in Linux

sudo apt install shc

Compile script file using shc

shc -f hello.sh

Check generated files

ls -l hello*
-rw-rw-r-- 1 user user    29 Mar 14 07:37 hello.sh
-rwxrwxr-x 1 user user 14960 Mar 14 07:39 hello.sh.x
-rw-rw-r-- 1 user user 10047 Mar 14 07:39 hello.sh.x.c

.sh is the original script.
sh.x is the compiled binary.
.sh.x.c is the C source code generated from the .sh file prior to compiling to .sh.x.

hello.sh.x permission is automatically set as executable

Rename executable

mv hello.sh.x hello

Check file execution

./hello Alice

References
https://www.simplified.guide/bash/compile-script

Assign Output of Shell Command To Variable in Bash

var=$(command-name-here)
var=$(command-name-here arg1)
var=$(/path/to/command)
var=$(/path/to/command arg1 arg2)

OR use backticks based syntax as follows to assign output of a Linux command to a variable:

var=`command-name-here`
var=`command-name-here arg1`
var=`/path/to/command`
var=`/path/to/command arg1 arg2`

Examples

## store date command output to $now  ##
now=$(date)
## alternate syntax ##
now=`date`

To display back result (or output stored in a variable called $now) use the echo or printf command:

echo "$now"
printf "%s\n" "$now"

References
https://www.cyberciti.biz/faq/unix-linux-bsd-appleosx-bash-assign-variable-command-output/

Set and Unset Local, User and System Wide Environment Variables in Linux

An environment variable can be in three types:
1. Local Environment Variable

a)

$ VAR1='TecMint is best Site for Linux Articles'
$ echo $VAR1
$ unset VAR1
$ echo $VAR1

b)

$ export VAR='TecMint is best Site for Linux Articles'
$ echo $VAR
$ VAR=
$ echo $VAR

c)

$ VAR2='TecMint is best Site for Linux Articles'
$ echo $VAR2
$ env -i bash
$ echo $VAR2

2. User Environment Variable

a) Modify .bashrc file in your home directory to export or set the environment variable you need to add. After that source the file, to make the changes take effect. Then you would see the variable (‘CD’ in my case), taking effect. This variable will be available every time you open a new terminal for this user, but not for remote login sessions.

$ vi .bashrc

Add the following line to .bashrc file at the bottom.

export CD='This is TecMint Home'

Now run the following command to take new changes and test it.

$ source .bashrc 
$ echo $CD

To remove this variable, just remove the following line in .bashrc file and re-source it:

b) To add a variable which will be available for remote login sessions (i.e. when you ssh to the user from remote system), modify .bash_profile file.

$ vi .bash_profile

Add the following line to .bash_profile file at the bottom.

export VAR2='This is TecMint Home'

When on sourcing this file, the variable will be available when you ssh to this user, but not on opening any new local terminal.

$ source .bash_profile 
$ echo $VAR2

Here, VAR2 is not initially available but, on doing ssh to user on localhost, the variable becomes available.

$ ssh [email protected]
$ echo $VAR2

To remove this variable, just remove the line in .bash_profile file which you added, and re-source the file.

NOTE: These variables will be available every time you are logged in to current user but not for other users.

3. System wide Environment Variables

a) To add system wide no-login variable (i.e. one which is available for all users when any of them opens new terminal but not when any user of machine is remotely accessed) add the variable to /etc/bash.bashrc file.

export VAR='This is system-wide variable'

After that, source the file.

$ source /etc/bash.bashrc 

Now this variable will be available for every user when he opens any new terminal.

$ echo $VAR
$ sudo su
$ echo $VAR
$ su -
$ echo $VAR

Here, same variable is available for root user as well as normal user. You can verify this by logging in to other user.

b) If you want any environment variable to be available when any of the user on your machine is remotely logged in, but not on opening any new terminal on local machine, then you need to edit the file – '/etc/profile'.

export VAR1='This is system-wide variable for only remote sessions'

After adding the variable, just re-source the file. Then the variable would be available.

$ source /etc/profile
$ echo $VAR1

To remove this variable, remove the line from /etc/profile file and re-source it.

c) However, if you want to add any environment which you want to be available all throughout the system, on both remote login sessions as well as local sessions( i.e. opening a new terminal window) for all users, just export the variable in /etc/environment file.

export VAR12='I am available everywhere'

After that just source the file and the changes would take effect.

$ source /etc/environment
$ echo $VAR12
$ sudo su
$ echo $VAR12
$ exit
$ ssh localhost
$ echo $VAR12

Here, as we see the environment variable is available for normal user, root user, as well as on remote login session (here, to localhost).

To clear out this variable, just remove the entry in the /etc/environment file and re-source it or login again.

NOTE: Changes take effect when you source the file. But, if not then you might need to log out and log in again.

References
https://www.tecmint.com/set-unset-environment-variables-in-linux/

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" "[email protected]"

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