Bash automation basics and scripting (part 3)

Contents

Shutterstock / Mopic

In this final post of our 3-part basics of automation and bash scripting series, we'll explore script debugging, running scripts as a background procedure and importing other scripts using source command.

Bash automation basics and scripting

If you want to start at the beginning, lea nuestro post Bash Automation and Scripting Basics Part 1. This final post in our three-part series on bash automation and scripting basics will discuss running scripts as a background procedure..

We also want to quickly debug our scripts with a minimum of complications and high-end results.. This can be done using a very useful trace function, built directly into the bash shell. We will see this in the second topic. You can also stay tuned for our next post on the related shellcheck.

And to finish we will explore how to run scripts as a background procedure. Although this can provide modest immediate benefits, how to start multiple tasks at the same time, also lays some of the foundation for later more advanced multithreaded scripts.

Script debugging

Debugging a script in bash doesn't have to be difficult!! Keep an eye on the CloudSavvyIT web portal, as we will soon review the most comprehensive shellcheck debugging tool for Bash, but for the moment I would like to introduce you to a great way to debug Shell scripts in a simple and easy to understand way.

Inside Bash's shell, that after all is a “simple” binary running on your machine, In other words, the bash tracks, an option is provided (-x) that, according man bash (running this in your terminal will show a manual Bash) is described as Print commands and their arguments as they are executedAnd this is exactly what it does!! How will this help with debugging?? Take a look at the following example:

#!/bin/bash

A=1
B=2
if [ "${AA}" == "1" -O "${B}" == "1" ]; then 
  echo "One ('1') was definitely stored in either the variable A, or the variable B"
  exit 0
else
  echo "Assert: could not locate the value '1' in the variables A and B"
  exit 1
be

A small Bash script with an error

Here we check the variables A and B against value 1. the -o idiom in the if declaration means OR, In other words, the first part (A, or better AA here it is 1) It's true, or the second part (B it is 1) is true and, in such a case, success is achieved.

The output of the script will be the scheduled assertion and the program will terminate with an exit code of 1, which generally means that there was an error. If the script had worked correctly, a confirmation message would be displayed and the script would terminate with an exit code of 0, which generally means that anything that was intended to be done with the script or the utility was successful.

Then, Why is the script running on assertion? You may have already noticed that the variable A I found a typo in our if statement, registered in code as AA: an insect! We could go and check the script, and if it is as short and simple as the one shown here, the error would be found quickly. But for a program 5000 lines, The answer is not so simple, especially if you use multiple threads, complex sublayers, etc.

We debug this now with the -x option to Bash. You may recall from the second part of our Bash Scripting and Automation Basics course that a subshell can be started using a $( ... ) set of idioms. It can also be started by simply typing bash, o for this case bash -x inside our upper shell. In this circumstance, we will execute the script inside our Bash subshell, with the -x option to observe what happens step by step.

Running our smalls script with bash -x

So we execute bash -x ./test_debugging.sh and notice the next conditional check is taking place: '[' '' == 1 -o 2 == 1 ']'. We notice that something is wrong: the value of 2 is being compared to 1 in the second part of our conditional check, but what is happening in the first part? Something is being compared to 1, but that something is … empty (as indicated by the empty string '')!

Then we check our script why that empty place is there and why it was not filled with the value of our A variable. We quickly realize the AA instead of A error, fix the error and the script now works fine.

The script fixed with the bug fixed.

Something really cool to remember when using bash -x is that you can tee (read this like 'Copy’) the output of the Bash command redirecting stderr (the error output) a stdout (standard output) and capturing the same with tee:

Using tee in combination with bash -x

Here we are running our fixed script and redirecting the error output (bash -x sends all your informational debugging output to stderr, the standard error output, y no a stdout) using 2>&1 (which redirects our stderr output to stdout – our standard output – instead). Then we capture stdout using tee and this will save the output to the specified file, namely bash_-x_output.txt.

This makes it possible for a bash developer to slowly review, in a step-by-step format, your written code. Especially when programs get complex, have functions, become multithreaded, start background processes, etc., this form of debugging can be very valuable. As an example, I tend to use bash -x about once every fifteen days to debug complex scripts.

Execution of scripts as background processes

Running a script as a background procedure is simple: just add & at the end of the script name (with a space between them). Define background.sh as follows:

#!/bin/bash

sleep 2

Then we start it the next way, to highlight the fact that it is running in the background:

Flow multiple Bash commands with one of those commands as a background process

What we can see happening here is as follows:: background.sh The script starts in the background (given the & attached to the script name with a space), and immediately the command prompt will return. We use this here by specifying the following command (sleep 1) directly after & background language, which also ends that command a single command / unique (In other words, sleep 1 it's an absolutely new command).

We also terminate our sleep 1 command with a frequent end of command Bash idiom, after which we will run a echo that he sleep 1 It's complete / done. Next, let's see what happens in the execution of this line.

Immediately, our procedure / script in the background (background.sh) starts up and will run for about 2 seconds. The PID (procedure identifier) of the started background procedure is displayed visually (In other words, 773183 for our first[1]) background procedure, and this PID will be different every time you start a program / background procedure), and ours sleep 1 (the next instruction for execution) now it can be executed since the other program has returned our message (even though it is not shown directly here, this is what happens when you start a background procedure; immediately gets command prompt back).

the sleep 1 starts (with the sleep 2 or more exactly the background.sh Script is still running in the background, as a different procedure, in a sublayer started under this upper or higher level layer) and ends after 1 second. After this our echo runs, showing us the sleep 1 Is complete. A second later, our background.sh the procedure rounds out your wait for 2 seconds and ends.

We do not see that it has finished since the Bash shell expects some interaction to show us status messages. Because, as soon as we press enter, anytime after the two-second sleep ends, we will see the termination of the background procedure as a [1]+ Done ./background.sh status message. If you go back to the second part of our miniseries, it is possible that he also sees how we could have used wait here to wait for completion / background procedure PID termination. It also highlights how many commands and utilities can be used in a combinatorial way in Bash.

Importing scripts using source

Importing another script can be done easily using Bash source command. Consider the following hyphen testsource.sh:

#!/bin/bash

source mysource.sh

echo "${MYVAR}"

And pairing mysource.sh:

#!/bin/bash

MYVAR="Hello CloudSavvyIT Readers!"

If we simply do the first script (testsource.sh) executable (using chmod +x testsource.sh), but not the second script (actually, we disassembled the executable flag to clearly show that this works using chmod -x upon mysource.sh), the second script is still called correctly as a result of the source command, and runs as part of the testsource.sh text:

Getting a script with the Bash source command

At mysource.sh script, we set the variable MYVAR for Hello CloudSavvyIT Readers!. This script is obtained later from testsource.sh script using instruction source mysource.sh. This will cause mysource.sh to be executed at that point the code, and when it's complete, the testsource.sh The script will continue to run, even though anything established in the mysource.sh will be retained (think of this as from another script to remember the operation of this more easily).

In summary

We take a look at debugging scripts using bash -x to show all commands executed. We also explored how to run a script as a background procedure and learned how we can import scripts using source code.. Thanks for being attentive to this series of 3 parts, Of which this was the final post!

If you are interested in learning more about Bash, How about check out our posts or Primer: Bash Loops: for, while and until, Conditional tests in bash: if, then, else, elif and Bash Local functions and variables

Subscribe to our Newsletter

We will not send you SPAM mail. We hate it as much as you.