Wednesday, January 11, 2017

Bash - Command Substitution, Subshell and Codeblock

Quick and simple differences between using $(..)(..) and {..;}.
  • $(command) or `command` - Command substitution (the output of a command replaces the command name) and is executed in a subshell. Please give preference to $(..) for better readability
  • ( command ) - Command list is executed in a subshell
  • { command ;} - Command list is executed in the current shell
Executing code
$ ( echo 123 )
123

$ $(echo 123) # this executes the output of the command
123: command not found

$ { echo 123 ;}
123
Fiding subshell level with built-in BASH_SUBSHELL variable
$ ( echo $BASH_SUBSHELL )
1
$ ( ( echo $BASH_SUBSHELL ) )
2

$ $($BASH_SUBSHELL)
1: command not found

$ { echo $BASH_SUBSHELL ;}
0
Passing variables to subshell
$ var1=1

$ ( echo $var1 )
1

$ $(echo $var1)
1: command not found

$ { echo $var1 ;}
1
Changing and getting variables values in subshell
$ var=1

$ ( var=2 ) ; echo $var
1

$ $(var=2) ; echo $var
1

# Because we did not create a subshell, 
# variable is available to original shell
$ { var=2 ;} ; echo $var 
2

Other usages

Example 1:
Multiple commands and multiple lines. This can be used with (..) and {..}.
$ { echo 1 ; echo 2 ; echo 3; }
1
2
3

$ { 
> echo 1
> echo 2
> echo 3;
> }
1
2
3
Example 2:
Changing the environment for subshell with separate environment. Here, set -u is only set in the subshell, so only the first echo will error out.
unset var1 var2
(
  set -u
  echo $var2
) 
echo $var1

Friday, December 23, 2016

Redirecting Bash xtrace to a separate log

So you have a Bash script that you want to troubleshoot, but you want to send stdout to a file, and stderr to another. Here's a solution.
For example, I like to use Bash's color to display failure or success on checks, and echo's removal of new lines (echo -e "Wait for it...\c ") to wait for checks. For example, the screenshot below shows a script that check each step and report back.
terminal
Errors are displayed in red, and success in green, and this same output is sent to the stdout and to a log file as well.
Now I want to get error messages in a separate log file, so I can go back to my original log and match the time where it failed, with additional verbose from Bash's xtrace.
The solution is very simple... I can just add the lines below to the top of my script:
# Debugging
debug_log="${HOME}/bin/log/script.debug"
exec 2>>${debug_log}
set -x
The first line setups my debug log, the second redirects stderr to my debug log, and the third enables xtrace (same as bash -x [script]).
Note that doing this will disable any errors from being show in stdout.

Wednesday, November 2, 2016

How to Record and Share a Terminal Session

A while ago I had shared instructions on "How to Share a Terminal Window Online". This is great for live support.
Today I'm sharing instructions on how to record your terminal session, and not only share it, but also allow users to copy and paste text from the playback video.
The installation could not be easier. And to show how great this utility is, I'm showing the instructions using a "video" recorded with "showterm".


Now go ahead and try copying text from the video. Isn't that great!?

Reference:
http://showterm.io/
https://github.com/ConradIrwin/showterm

Wednesday, October 19, 2016

How to Create A Prompt With Timeout in Bash

Here's a quick function that will display a prompt with timeout in a bash script:
_myCountdownFunction () {
echo -e "Hit \"Ctrl+c\" to quit or \"Enter\" to continue...    \c" 
cnt=5
while (( cnt >= 0 )) ; do
  if (( cnt < 9 )) ; then
    echo -e "\b\b${cnt}s\c"
  elif (( cnt == 9 )) ; then
    echo -e "\b\b\b ${cnt}s\c"
  elif (( cnt <= 99 )) ; then
    echo -e "\b\b\b\b ${cnt}s\c"
  elif (( cnt < 999 )) ; then
    echo -e "\b\b\b\b${cnt}s\c"
  fi
  read -t 1 my_reply
  (( $? == 0 )) && exit 1
  let cnt-=1
done
}

The user will see the following message on his terminal with the seconds counting down in place:
Hit "Ctrl+c" to quit or "Enter" to continue... 5s

At the end of the specified time in 'cnt', the script (where the function would be) will continue executing, and if the user hits "Ctrl+c" before that, it will exit (both script and function).
The function supports up to 999s (which should be enough).

Friday, September 2, 2016

How to Create a Quick Web Server

Have you ever had the need to create a web server to perform a test? Well, here are a few quick options on how to do this.

Got Netcat?

If you have Netcat on the server (which is pretty easy to get), then you can do this.
Example 1: Display the date and the text "It works"
nc -kl 10001 -c 'echo -e "HTTPS/1.1 200 OK\r\n\r\n$(date)\r\n\r\nIt works"'
Example 2: Display an index.html file
nc -kl 10001 -c 'echo -e "HTTPS/1.1 200 OK\r\n\r\n$(cat index.html)"'
Example 3: Using HTTPS
a. First get a set of self-signed certificate and key (either generate or download here -http://www.selfsignedcertificate.com/)
b. Add the certificate to the server and run netcate with the following parameters
nc -l -p 10001 -k --ssl --ssl-cert ca.crt --ssl-key ca.key -c 'echo -e "HTTP/1.1 200 OK\r\n\r\n$(date)\r\n\r\nIt works"'

Python

This is the easiest one, as long as you have Python on that system. Just run the commands below and you are set. If you have an index file on that folder, Python will display, otherwise it will do a directory listing.
$ python -m SimpleHTTPServer 8888
Serving HTTP on 0.0.0.0 port 8888 ...