قالب وردپرس درنا توس
Home / Tips and Tricks / Basics of bash automation and scripting (part 2) – CloudSavvy IT

Basics of bash automation and scripting (part 2) – CloudSavvy IT

Shutterstock / Mopic

Bash is an ideal shell and coding language for creating advanced automation scripts. In this second part of the series, we’ll look at encoding density, inline comments, and how to correctly quote variables with single or double quotes.

Bash automation and scripting basics

If you haven̵

7;t already done this and are just getting started with Bash, read our article on Bash Automation and Scripting Basics, Part 1. This is the second article in our three-part series on Bash automation and scripting basics. In today’s article, we’ll look at Bash encoding density and its relationship to developer preference, among other things. In connection with this, we will also review inline comments.

Once we start creating small scripts, exploring variables, and working with text strings, we quickly realize that there can be a conceptual difference between single and double quotes. There is, and we’ll get into it in the second topic below.

Bash encoding density and brevity

The Bash coding language can be very compact and concise, but it can also be spacious and comprehensive. It largely depends on the developer’s preference.

For example the following Bash code:

true || echo 'untrue'

Which can be read as Do nothing, and do this successfully (exit code 0), and if that should fail (maybe read the Bash idiom || as OR) output the text ‘false’, can also be written as:

if [ ! true ]; then
  echo 'untrue'

Which makes the code a little different, but basically does the same thing.

This in turn can be read as If not true (indicated by the ! idiom) is true, then output the text ‘false’

Two ways to code in Bash;  same functionality, very different code

Both mini scripts result in the same empty output, such as true is not false

The multitude of commands and tools available (or installable) from and on the command line increase the potential offset between easy-to-read scripts and hard-to-understand, compact and concise code.

While the above examples are short and relatively easy to understand, when you create a long one-liner (a term often used by Bash developers to refer to a piece of code made up of multiple commands written on a single line) with many such commands, instead of putting the same thing in a more elaborate script, the difference becomes more apparent. To consider:

V="$(sleep 2 & fg; echo -n '1' | sed 's|[0-9]|a|')" && echo "${V}" | sed 's|[a-z]|2|g' || echo 'fail'

A complex one-liner example

This is a typical Bash one-liner script that uses the commands sleep fg echo, and sed as well as various Bash idioms and regular expressions to actually sleep for 2 seconds, run some text and transform this text by using regular expressions. The script also regularly checks the conditions / results of previous commands using the Bash idioms || if it doesn’t work, then do what follows) and && if this works, do the following

I translated this, with estimated matching functionality, into a more complete script, with some tweaks. For example, we have our fg (Bring the sleep command placed in the background back to the foreground, and wait for it to finish as normal non-background processes) to wait which will wait for the PID of sleep (started by eval and captured using Bash’s idiom $!) to end.


CMD="sleep 2"
eval ${CMD} &
wait $!

V="$(echo -e "${CMD}n1" | sed 's|[0-9]|a|')"

if [ ${EXIT_CODE} -eq 0 ]; then
  echo "${V}" | sed 's|[a-z]|2|g'
  if [ ${EXIT_CODE} -ne 0 ]; then
    echo 'fail'

Instead, the same complex on-line in a full script

Quite a difference! And this is correct a developer who writes it are goneBash code written by others tends to be somewhat challenging to read, and such difficulty quickly increases with density and brevity. Still, an expert-level developer in Bash will quickly understand even very dense and concise code written by others, with some exceptions, such as regular expressions.

To learn more about writing regular expressions, see Editing Text Using Regular Expressions Using the sed Stream Editor.

These examples show that your mileage will vary over time. In general, however, peer-friendliness (by writing highly readable code) is recommended when you start developing Bash scripts.

If you need to create dense and concise code, you can provide many inline comments. A line preceded by a # is considered a comment / comment line, and the symbol # can even be used towards the end of a line after an executable command, to put a suffix comment with an explanation of the command, conditional statement, etc. For example:

# This code will sleep one second, twice
sleep 1  # First sleep
sleep 1  # Second sleep

Single quotes or double quotes?

In Bash, text enclosed in single quotes (') are considered literal text by the Bash interpreter, while text enclosed in double quotation marks (") is interpreted (parsed) by the Bash interpreter. While the difference in how things work may not be immediately apparent from this definition, the following example shows us what happens when we exchange ' in front of " and vice versa:

echo ' $(echo "Hello world") '
echo " $(echo 'Hello world') "

Single quotes versus double quotes in Bash in a hello world example

In the first example, the text $(echo "Hello world") is treated as literal text, so the output is simple $(echo "Hello world") However, for the second example, the output is Hello world

The Bash interpreter parsed the text in double quotes to see if he would find any special Bash Idioms to act upon. One of those idioms was found in $( ... ) which basically starts a subshell and executes whatever exists between the ( ... ) idiom. Think of it as a shell within a shell – a subshell – and run whatever you pass to it as a completely new command. The output of such commands or commands is then sent back to the top-level shell and inserted in the exact place where the subshell was started.

So our subshell executed echo 'Hello world' whose output is Hello worldOnce this was done the subshell ended and text became Hello world is inserted instead of the $( ... ) subshell call (think about it like all $( ... ) code is replaced with the output that the subshell generated.

The result for the top shell is the following command: echo " Hello world ", whose output is Hello world as we saw.

Note that we have changed the double quotes in the subshell to single quotes. This is not necessary! You would expect to see a parsing error when a command exits the syntax of echo " ... " ... " ... ", in the sense that the second double quotes would end the first, followed by more testing, and thus lead to an error. However, this is not the case.

And this is not because Bash is flexible with multi-quote strings (it accepts echo 'test'"More test"'test' fortunately for example), but because the subshell is a shell per se, and thus double quotes can be used, again within the subshell. Let’s prove this with an additional example:

echo "$(echo "$(echo "more double quotes")")"

Bash easily accepts repeated double quotes in a subshell

This works fine and provides the output more double quotesThe two nested subshells (which run in the main shell from which you run this) each accept double quotes in turn and no errors are thrown even if multiple double quotes are nested over the common one-liner command. This shows some of Bash’s programming power.

In summary

After examining the coding density, we realize the value of writing highly readable code. If we do need to create compact and concise code, we can add a lot of inline comments using # to improve readability. We looked at single and double quotes and how their functionality differs significantly. We also looked briefly at inline comments in scripts, as well as subshell functionality when executed from a double-quote string. Finally, we saw how a subshell can use another set of double quotes without affecting the double quotes used at a higher level in any way. Stay tuned for part 3!

Source link