Posted on

Table of Contents

Bash is a shell with a scripting language that allows you to do things like concatenating commands. to make a script write your bash commands in a file. the first line of the file must contain a shebang: #!/usr/bin/env bash which tells the shell how to run the file.

This article uses primarily the gnu bash manual and the x in y minutes guide as sources and is meant to be an approximate overview.

streams

bash has three standard streams: stdin, stdout, and stderr. stdin is naturally where what the user types to console goes. stderr and stdout often both write to console. stdout is represented as the number 1 in certain cases and stderr as 2.

variables

variable assignment looks like name="value" but crucially cannot have spaces or bash will interpret the name as a command.

to dereference a variable and use its value write it as "$name" it must use double quotes and not single quotes, omitting the quotes is technically possible but not recommended.

arrays

you create an array much like a variable

array=(first second third)

and index into it like you expect array[0] but you can also return the whole array array[@] and index into a range of that array array[@]:0:2. You can also get the length of an array with #array[@]

arithmetic

check out the gnu manual for a full breakdown. I will just say its mostly what you expect. I will note that:

  • ** is power
  • >> << are bitwise shifts
  • | & are bitwise OR and AND while || && are logical
  • ^ is XOR
  • there is a ternary operator: condition?expr:expr
  • ~= lets you check a string against a regex

expansion

Is the process by which a pattern is expanded out into all the words it describes. (for example a regular expression expanded into the language it describes). See the gnu manual on expansion.

command substitution

$(<commands>)

Command substitution allows a command to be treated as its output. In other words you can execute a command in place and use its data as if it were a dereferenced variable.

parameter expansion

parameter expansion lets you modify a command's argument on the fly, as well as indirection, for instance:

var="hello world"
indirect="var"
echo "${var/hello/hey}" #=> hey world
echo "${!indirect}" #=> hello world
echo "${var:0:4}" #=> hello
echo "${var:-"default"}
# default value if var is missing or empty

brace expansion

Brace expansion is used to generate ranges of characters and numbers.

{1..5} #=> 1 2 3 4 5
{a..e} #=> a b c d e

you cannot use variables inside the brace expansion.

built in and environment variables

  • $? is the last program's return variable
  • $$ is the script's PID
  • $# number of arguments
  • $@ all arguments passed to the script
  • $1, $2 ... are the numbered arguments
  • $PWD is the working directory as a variable
  • $USERcurrent user's name
  • $PATH is a list of paths the shell will search for command executables
  • - is the previous working directory
  • .. is the parent directory
  • . is the current directory
  • ~ is the home directory

pipelines

The | character is called a pipe and directs the output of its left hand command into the input of the right hand command. |& is another type of pipe that also connects the left hand error to the right hand input. A series of commands connected by pipes is called a pipeline.

redirection

Redirects are similar to pipes but instead of hooking output into input, it hooks a file or stream into a command's input or output. > file allows an output to be written to a file, and < file allows a file to be used as input.

>> and << do the same but append rather than overwrite.

see more details at the gnu manual

lists

Lists are series of commands or pipelines connected together by list operators.

|| is the OR operator. It will execute its LHS and then execute its RHS if the LHS has a non-zero exit status (the command failed).

&& is the AND operator. It will execute its LHS and then execute its RHS if the LHS exited with a zero exit status (the command succeeded).

; is the sequence operator. It will run the LHS then the RHS regardless of exit status, it can be replaced with a newline.

& is like ; by executes the LHS in an asynchronous shell

process substitution

Process substitution allows you to treat the input or output of a process as a file name while running the process asynchronously. >(list) allows you to write to the input as a file. <(list) allows you to read the output of list as a file. there cannot be a space between the angle bracket and the left paren.

compound commands

These are code blocks that can hold multiple commands. Each compound command is begun and terminated by a reserved word or character.

looping commands

Bash has three loops: until, while, for.

until

until <condition command>;do
    <commands>;
done

The until loop goes until the condition command has zero exit status. The block inherits the status of its last executed command or zero if no commands were executed.

while

while <condition command>; do
    <commands>;
done

The While loop goes until the condition command has a non-zero exit status. The exit status of the block is the status of the last run command of the do block or zero if no commands were run.

for

for loops have two forms:

#iterator
for ((i=1; i<n; i++)); do
    <commands>;
done

#named variable
for <name> in <array>; do
    <commands>;
done

note that the array here can also be an expansion

conditional commands

arithmetic commands

((arithmetic expression)) evaluates the math and gives an exit status of zero if the arithmetic expression evaluates to a non-zero value and zero otherwise.

[[conditional expression]] evaluates a conditional expression and returns a 0 or 1 based on the result(0 is true and 1 is false).

if

if <condition command>; then
    <commands>
elif <condition>; then
    <commands>
else
    <commands>
fi

Note that elif and else are optional.

case

case <var> in
    pattern1) <command>;;
    pattern2) <command>;&
    pattern3) <command>;;&
    *) <default command>;;
esac

patterns can be regular expressions, or numbers.

select

Select is useful for creating menus. It prints all the options with in the given list with numbers to std err and waits for a number over std in. it then runs that commands and loops until a break command is selected

select <name> in <list>; do
    <commands>;
    break;
done

see the gnu manual on conditional commands for more.

groups

(list) causes all the listed commands to be executed in a subshell. {list;} executes the listed commands without a subshell. the trailing semicolon is required.

functions

define a function with

name () {
    return exit_status #return is not required
}
#or
function name (){ #note that in this case () is optional
    return exit_status
}

we don't actually put arguments in the parentheses since we refer to them with $1 $2 etc

to call a function we simply write its name and any arguments

func arg1 arg2

functions are scoped and have access to their parent scopes. However, local variables must be declared with the local keyword like so

var1="foo"
var2="baz"
func1() {
    local var1="bar"
    echo $var1 #=> bar
    func2 #=> bar
}

func2() {
    echo $var1
}

func2 #=> foo

func3() { var2="bat"; }
func4() {
    func3;
    echo $var2; #=>bat
    }

some commands/utils

  • cd path changes your working directory
  • ls lists the directories in the working directory
  • touch name creates a new file with name
  • mkdir name creates a new directory with name
  • mv path1 path2 moves the file at path1 to path2
  • cp same as move but doesn't delete the original
  • pwd prints working directory
  • echo prints its argument
  • grep allows you to search using pattern matching
  • sed allows you to match with pattern matching
  • uniq allows you to omit repeated lines
  • head and tail allows you to cat the first or last n lines of a file
  • cut prints a column of text from a file limited by a given delimiter.
  • jobs shows all running async jobs
  • cat path prints file to console
  • read var lets you read user input and store it in a variable
  • alias lets you name a specific command e.g alias hi=echo "hey"
  • trap allows you to execute a command on a given signal

you can end processes with ctrl+c and pause them with ctrl+z. ctrl+d sends an EOF token.