Bash Shell Scripting

What are Shell Scripts?

  • Files containing a series of commands
    • In other OSs they have the .sh extension
  • A shell is a program that passes commands to the operating system
    • You interact with the shell using the CLI
  • Shells and command languages are also scripting languages
    • You can write programs in Bash to be interpreted and executed by the shell
  • Before we start writing shell scripts, let's get used to a few awesome Bash concepts

Bash Tips

  • Your ~/.bashrc file gets read and its commands are applied whenever you start a shell session
    • ​This is where you'll put your settings and any shell functions (more on that later)
    • export EDITOR=/usr/bin/vim
    • ​bind "TAB:menu-complete"
    • bind "set show-all-if-ambiguous on"
    • bind "set completion-ignore-case on"
  • When writing long commands, you can hold Control and press 'x' then 'e' to edit the command in Vim
  • Ctrl+l to clear the terminal screen
  • !! is the last run command
    • Ex. sudo !! runs the last command as sudo (if you forgot to do so)

Control Operators

  • ; runs commands sequentially
    • command1 ; command2
  • & runs commands in the background
    • command1 & command2
  • && runs one command after another has successfully executed
    • command1 && command2
    • AND operator
  • || runs one command after another fails
    • command1 || command2
    • OR operator
    • Can also be written as an if else statement

echo & shell stuff

  • echo is a command that prints out its arguments into the command line
  • When you press Enter/Return, the shell translates whatever is typed in before it is interpreted. Try these:
    • echo hello world
    • echo *
  • * is an expansion that matches all characters in a filename, the shell doesn't literally read it as *, it reads it as the wildcard expansion results
    • ​​​echo ~/*

Expansions

  • Expansions are character sequences that are changed before the shell acts on it
  • $((arithmetic expression))
    • echo $(((5*5)+10)) is equal to 35
  • Brace expansion is great for working on multiple character sequences and files
    • Separate the different arguments in the curly braces with commas and NO SPACES
    • You can use .. to produce a range of numbers/letters
      • echo front-{A..D}-back
        
      • echo number{1..7..2} 
      • touch {john.py,irene.py,yukio.py}
      • rm {john,irene,yukio}.py

More Shell Stuff

  • Parameter expansion uses variables for Bash
    • Use the printenv command to see environment variables
    • Variables are denoted with a $
      • echo $USER
      • echo $PATH
        • The PATH variable is very important! You'll see why soon

  • Command substitution allows you to use a command's output as an expansion
  • $(command)
    • echo $(ls)
    • sudo pacman -R $(pacman -Qdtq)

Writing Shell Scripts

  • The first line of every shell script should be a shebang (#!)
    • Tells the shell which interpreter to use
    • #!/bin/bash
  • Like Python, you comment lines in Bash with #
    • Not to be confused with #!
  • Let's write our first simple shell script: hello_world
#!/bin/bash

echo "Hello World!"

Executing Shell Scripts

  • Before we run our shell script, we have to make it executable
    • Remember file permissions? ls -l
  • chmod +x hello_world
    • You could also use the octal modes 755 or just 700
  • Now let's run our script!
    • ./hello_world
    • The "./" is writing out the relative path, . denotes the current directory

Script Location

  • Why did we have to write the path instead of just typing in hello_world?
    • Remember the PATH environment variable?
      • echo $PATH
    • Whenever you execute a command, the shell searches through the directories in the PATH variable for an executable program. Having the path written out gives the system the file
  • If you don't want to have to write the path, you can move the script into one of those directories (like /bin or /usr/bin), or add a directory to your $PATH

Adding Paths to $PATH

  • You can either add the path to the beginning or end of the PATH variable
    • The order matters for which directories get searched first
  • Add to your .bashrc:
    • export PATH=/path/you/want:$PATH
    • export PATH=$PATH:/path/you/want

Variables

  • Like Python, Bash creates variables as they are encountered during assignment
  • variable=value
    • No spaces!
  • Call the variable how you normally would in Bash
  • Unless specified otherwise, all data in variables are stored as strings
#!/bin/bash

title="Detailed Contents of Directory"
stuff=$(ls -alh)

echo "$title

$stuff"

Here Documents

  • Another way to output text other than echo is using a here document
    • Embeds a body of text into the script and feeds it to the standard input using redirection
      • command << token
      • text
      • token
    • command is a command that accepts stdin (like cat) and token is a string that's used to indicate the end of the text
      • _EOF_ is usually used as a token, meaning end of file
  • Pretty much the same as echo, except single and double quotes aren't expanded and lose their meaning to the shell

Here Documents

#!/bin/bash

title="Detailed Contents of Directory"
stuff=$(ls -alh)

cat << _EOF_
$title
"Here is a list of"
'the contents of the pwd'
    yay!
$stuff
_EOF_

# Change the redirection operator to <<- if you
# want to ignore leading tabs for formatting

Scripting Review Exercise

Create a script that generates a System Information Page. The page should display a timestamp of when it was created (and by who), the shell you're using , how long the computer has been on, and disk space usage.

  • Use a here document
  • Use the following variables:
    • $USER, $SHELL
    • Create 2 of your own
  • Use the following commands:
    • df -h
    • date
    • uptime -p
  • For the HTML: Use <h1>, <h2>, <p>, and <pre> tags
<!--The HTML skeleton-->

<html>
    <head>
        <title></title>
    </head>
    <body>
        page content
        goes here
    </body>
</html>

Shell Functions

  • Shell functions are like functions in Python, except they're written as "miniscripts" located inside of scripts that can act as programs
  • There are 2 different ways to define functions
function name {
    commands
    return
}

name() {
    commands
    return
}

# call functions by 
# writing the name

name
  • name is the name of the function
  • commands is the series of commands executed by the function
  • return is optional
  • Local variables are defined with the keyword local preceding the name

Function Positional Parameters

  • Shell functions can take in command line arguments
    • Use the variables $1, $2, $3, ..., $n to access the arguments based on its position
    • Call the function like so: functionName foo bar
      • foo is the first argument that is stored in $1
      • bar is the second argument that's stored in $2
  • Special variables:
    • $0 holds the command/function name
    • $* or $@ holds all parameters/arguments passed to the function
    • $# holds the number of positional parameters passed to the function

Shell Functions in your .bashrc

  • Shell functions can be written in your .bashrc to be executed as commands
  • Great replacement for aliases
    • Aliases are limited in shell features, functions are not
  • Useful Exercise:
    • Write a function cd() in your .bashrc  that automatically executes ls whenever you cd into a directory
    • Hint: Use the builtin keyword so your function isn't recursive and runs forever
  • Since your .bashrc is read whenever you start a new shell session, you have to open a new terminal or source the file to use your new function
    • source ~/.bashrc

read

  • read is a built-in command that reads a single line of keyboard input and stores it in a variable(s) that's passed in as an argument
    • read [-options] [variables]
    • A lot of the options are really useful, look them up!
#!/bin/bash

echo -n "Please enter a word: "
read word

echo $word

test

  • The best command to use with if statements (covered next) is test
    • ​[ expression ]
    • test expression
    • expression is an expression that's evaluated as either true or false
  • Check the manual for test to see how to use it!
    • man test
    • Test equality/inequality in strings and integers
    • Evaluate the status of files

if Statements

# Syntax of if statements

if commands; then
    commands
elif commands; then
    commands
else
    commands
fi
python=5

if [ $python == 5 ]; then
    echo "Python is cool"
elif [ $python == 6 ]; then
    echo "Python isn't cool"
else
    echo "C is annoying"
fi
  • commands is a list of commands
  • You can also enter it directly into the command line with ; as the newline separator (not after the then though)
  • The shell evaluates the success or failure of a command through the exit status

Exit Status

  • When a command (or shell function/script) finishes executing and terminates, it issues an integer in the range of 0 to 255 to the system called the exit status
    • 0 indicates success
    • Any other number (1-254) indicates failure
  • The variable $? holds the value of the exit status
  • The commands true and false always terminate with a 0 and 1 exit status, respectively
    • true
    • echo $?
    • false
    • echo $?

Scripting Review Exercise

Write a shell script that takes gives the user 5 seconds to enter a number, and then prints out whether that number is even or odd

Write a function for the above shell script that requires the user to input a predefined password to use the script

Other ways to use test

  • A more modern, enhanced replacement for test
    • [[ expression ]]
    • Supports all test expressions/arguments, but has a couple of additions
      • string =~ regex where regex is an extended regular expression; used for data validation

      • The == operator supports pathname expansion *

  • Operate on integers with ((  ))
    • ​Performs arithmetic truth tests
      • Ex. if ((INT == 0)); then echo "INT is zero"; fi

  • Combine expressions using the && and || operators
  • ! is the NOT operator

Bash Shell Scripting

By jtheadland

Bash Shell Scripting

  • 622