# Overview

Historically I’m a Windows developer (C/C++/C#). I’ve been using more and more Linux tooling and, day by day, the Linux learning is creeping in. A massive sprawling knowledge space, unfamiliar to me. But over and over again there are some basic bash scripting techniques I need, this is them.

Assumptions: you have written some kind of code before.

My examples are tested using Bash on Ubuntu on Windows. bash version 4.3.11 use bash --version to find this.

## Variables

### Basics

context bash
Simple someVar=a_value
Double quotes " someVar="use quotes if you need spaces"
Single quotes ' someVar='quotes with spaces'

🗒 Note: no space between variable name or equals and value.

To reference the variable prefix with a $ as below. A variable may be constructed from others and is evaluated upon construction h=hello w=world # variables expanded using double quotes hw="$h $w" # single quotes means no variable expansion wrong='$h $w' # displays hello world echo$hw

# displays hello world
echo "$h$w"

# displays $h$w
echo $wrong  Clear a variable with unset, e.g. unset someVar. Alternatively use someVar=, there appears to be no difference. 🗒 Note: the lack of $ prefix when using unset.

### Environment vars

A script cannot set any environment variables in the calling parent scope, just as in Windows.

A script can set environment variables in a child process through the export command.

someVar="a child process needs this"

### Parameter expansion

The basic variable expansion as above with the echo is just the tip of the iceberg.

The motivation for this blog post was initially this very topic. I’d seen both $someVar and ${someVar} used apparently interchangeably and without rhyme or reason. This is what it is really used for.

The bash interpreter will attempt to find a variable named following the $. In some cases it is not possible to parse this, e.g. h="hello " # this fails echo "$hworld"
# need to wrap the variable in {}
echo "${h}world"  Using the {} syntax we can apply transforms to the variable contents: • ^ uppercase • , lowercase • ~ swap case Use 1 (for the first character only) or 2 (the whole value) of the transform symbols. e.g. x="Abc" y="xyZ" echo "${x} ${x,}${y~} ${y^^}" # output: Abc abc XyZ XYZ  Arithmetic expressions must be wrapped inside $(()).

a=12
b=4
echo $((a+b))$((a/b))
# output 16 3


Other expansions include extracting a substring, regular expressions, default values. See a great explanation here

## Conditionals (aka tests)

🗒 Note: The history of the syntax is described in the bash hackers Wiki. Understanding that helped my understanding.

# this is a comment, you get the idea.

# strings
x="a string"
if [ $x == "a string" ] then echo "x is correct" fi # eq works with numbers too x=42 if [$x -eq 42 ]
then
echo "x is correct"
fi

# in one line
if [ $x == 42 ];then echo "x is correct";fi  🗒 Note: It is really important to leave a space between the opening [ and the first part of the expression and the last part of the expression and the closing ] If you get the error bash: [: too many arguments, consider how the parts between the [] are being expanded as arguments to the [ aka test build-in command. ## Functions a="global value a" b="global value b" echo "a=$a b=$b" a_function () { a="global changed within function" local b="locally scoped b" echo "Doing it...first arg was$1"
echo "a=$a b=$b"
return 4
}

a_function "hello"

echo "a=$a b=$b"

echo "Done $?"  Output a=global value a b=global value b Doing it...first arg was hello a=global changed within function b=locally scoped b Done 4 a=global changed within function b=global value b  Notes: • The spaces in the function declaration are required • The return value is optional but must be numeric (like a standard cli command) • The $? built-in variable collects the return value for the last command or function
• arguments are by position, rather than explicitly named and accessed using \$n where n is their 1 based index
• local is used to scope variables to a function
• globals are accessible for read and write within a function

## Enough …

… for now. Looping, capturing literal expressions, using sed and curl are all really useful. I still keep using dir or ls when I mean find, grep seems to get complicated when you stray from the simple stuff and jq is super powerful but it’s usage is completely ‘read the docs’ driven.