Programming/Bash: Difference between revisions

From Dev Wiki
Jump to navigation Jump to search
(Start unittesting docs)
(Move unittesting contents to new page)
 
(One intermediate revision by the same user not shown)
Line 231: Line 231:


== Unit Testing ==
== Unit Testing ==
The UnitTesting I've found in Bash is to use '''Bats'''. Full description found at https://opensource.com/article/19/2/testing-bash-bats.
See [[Programming/Bash/Unit Testing|Unit Testing]].
 
Effectively, first add [[Programming/Git Submodules|Git Submodules]]:
git submodule add https://github.com/sstephenson/bats tests/libs/bats
git submodule add https://github.com/ztombol/bats-assert tests/libs/bats-assert
git submodule add https://github.com/ztombol/bats-support tests/libs/bats-support
git commit

Latest revision as of 20:58, 25 October 2020

Bash is primarily a Linux scripting language, but it works on all versions of Windows as well, if used through git.

File Start

Unless you have explicit reason for otherwise, essentially all bash files can safely start with the line:

#!/usr/bin/env bash

It essentially tells your script what interpreter to use when executing the file.

Comments

Inline Comments

# This is an inline comment.

Block Comments

Block level comments don't truly exist in Bash.

However, there is a hackish way to implement them anyways, according to https://stackoverflow.com/a/43158193

Warn: It's recommended to use multiple inline comments instead, as this may not always work with all systems.
: '
This is a block comment.
Comment line 2.
Another block comment line.
'

Variables

For variable definition, note that spacing is important. Spacing around the equals sign will break the assignment.

Variable Definition

a_bool=true
b_bool=false
my_var_1="This is "
my_var_2="a string."

Variable Usage

In bash, there is an optional bracket ${} syntax. It's recommended to use when using a variable alongside other values, on a single line.

Below is an example of both minimal syntax and ${my_var} syntax.

echo "Printing variable values."
echo $a_bool
echo $b_bool
echo ${my_var_1}${my_var_2}

Local Variables

By default, any variable in a bash script is a global variable.

ToDo: Link to "global/local variable" documentation.

To limit a variable to local scope, use the local syntax.

For example, below defines two variables with a value of "5". One is global and one is local:

my_global_var=5
local my_local_var=5

Passing Variables into the Script

It's possible to pass variables directly from the command line into a given bash script. To do this, type the command to execute the script, followed by all the args you wish to pass in.

For example, if your script name is my_script.sh, then you might have the following:

./my_script.sh test 5

This will pass in the arguments of "test" and "5" into your script.

Accessing Variables Passed into the Script

You access passed variables via the dollar sign, followed by the argument number.

For example, in the above scenario, we passed in values "test" and "5" as the first and second arg respectively. To access them, we could use:

echo $0    # Prints out our script name, "my_script.sh".
echo $1    # Prints out "test".
echo $2    # Prints out "5".

You can also get all passed variables in array format, with the ${@} variable.


If Statements

Basic If

if [[ $x == $y ]]
then
    # Logic if true.
fi

Full If

if [[ $x == $y ]]
then
    # Logic for "if" true.
elif [[ $x && ($y || $z) ]]
then
    # Logic for "else if" true.
else
    # Logic for false.
fi

File and Folder Checks

For a full list of built-in args to check file and folder status, see https://www.gnu.org/software/bash/manual/bash.html#Bash-Conditional-Expressions


For Loops

for <loop_variable> in $<my_iterable_object>
do
    # Logic to execute on each loop.
done

For example:

for item in $my_list
do
    echo $item
done


Functions

function <function_name> () {
    # Function logic here.
}

Passing Parameters

Passing variables into functions in Bash is a bit...obtuse, for lack of a better word.

Essentially, each function is almost treated as a new instance of a bash script. So functions use the same syntax to pass variables into the script.

For example, if we have test_function and we want to pass two variables, then the code may look like this:

 function test_function () {
    var_1=$1
    var_2=$2
}

To call this function, we would have code like this:

some_var_1="test"
some_var_2=5
...
test_function $some_var_1 $some_var_2


Data Structures

Arrays

Arrays are one of the most common data structures. See Arrays for more info.

Arrays in Bash are a bit strange, syntactically. For an in-depth explanation, see [1].

Having said that, Bash arrays start at the 0 index. And they can hold elements of different types.

Declaring Arrays

Declare an array by normal variable declaration, with the a list of values between two parenthesis. Note that the list items should only be separated by spaces, with no commas between.

my_array=(1 2 3 4 5)

Accessing Array Values

Arrays in Bash are one of the only variable types that require the bracket syntax.

To append new index values, use:

my_array+=<value>

To read all values in the array, use:

${my_array[@]}

To read a single index, use:

${my_array[<index>]}

To update a single index, use:

my_array[<index>]=<value>

Bash arrays aren't meant to be mutable, and thus don't really have a good way to remove an index. The best alternative is to create a second array that only has the values you want.

Dictionaries

Dictionaries can be incredibly powerful. See Dictionaries for more info.

Declaring Dictionaries

Dictionaries in Bash are called "associative arrays" and are declared with the following:

declare -A my_dict

Accessing Dictionary Values

To set new key-value pairs, use:

# Set multiple key-value pairs.
my_dict=( [<key_1>]=<value_1> [<key_2>]=<value_2> )

# Set a single key-value pair.
my_dict[<key>]=<value>

To read all key-value pairs, use:

# Expand all keys in pair.
${!my_dict[@]} 

# Expand all values in pair.
${my_dict[@]}

To read a value in a key-value pair, use:

${my_dict[<key>]}

To update an existing key-value pair, use

my_dict[<key>]=<value>

Bash arrays aren't meant to be mutable, and thus don't really have a good way to remove an index. The best alternative is to create a second array that only has the values you want.


String Manipulation

See https://stackoverflow.com/a/14703709

With bash, it's possible to dynamically trim strings, based on regex matches.
The syntax is:

# Trim shortest match from beginning.
${<string_value>#<regex>}

# Trim longest match from beginning.
${<string_value>##<regex>}

# Trim shortest match from end.
${<string_value>%<regex>}

# Trim longest match from end.
${<string_value>%%<regex>}


For example, if you have a string of

file_name="/home/user/my_dir/my_dir/my_file.tar.gz"

Then you can do the following manipulations:

# Get the full file extension.
# Outputs "tar.gz"
${file_name#*.}

# Get the last part of the file extension.
# Outputs "gz"
${file_name##*.}

# Get the full file name, including file extension.
# Outputs "my_file.tar.gz"
echo "b: ${file_name##*/}

# Get parent of current directory.
# Outputs "/home/user/my_dir/"
${file_name%my_dir/*}

# Get grandparent of current directory.
# Outputs "/home/user/"
${file_name%%my_dir/*}


Unit Testing

See Unit Testing.