Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

How can I automate things with bash?

So far we have used bash commands to navigate our file system as a way to learn about the file system itself. To do this we used commands like:

Solution to Exercise 1

command

explanation

pwd

print working directory

cd <path>

change directory to path

mkdir <name>

make a directory called name

ls

list, show the files

touch

create an empty file

echo 'message'

repeat ‘message’ to stdout

>

write redirect

>>

append redirect

rm <file>

remove (delete) file

cat

concatenate a file to standard out (show the file contents)

mv <old_path> <new_path>

Moves file from path to another (can be used to rename only)

cp <file> <path>

Copies the content of the file from into a new file (can be with or without the same name)

find <pattern>

search the file system (paths) for matches to a pattern

Bash is a unix shell for the GNU operating system and it has been adopted in other contexts as well. It is the default shell on Ubuntu linux as well for example (and many others). This is why we teach it.

A Unix shell is both a command interpreter and a programming language. As a command interpreter, the shell provides the user interface to the rich set of GNU utilities. The programming language features allow these utilities to be combined.

Read the official definition of bash and a shell in the bash manual

Inspecting an example script

Today we will start by inspecting the github action file, first we’ll navigate to the folder.

cd fall25-kwl-brownsarahm/

We want to look at a file if we get this far and then press tab mulitple times, it will show us the options

cat .github/workflows/
create_about.yml         forgottenexperience.yml  logger.yml
experienceinclass.yml    getassignment.yml        
experiencereport.yml     label_badges.yml

Then we will look at the getassignmet one.

cat .github/workflows/getassignment.yml
name: Create badge issues (Do not run manually)
on:
  workflow_dispatch

# once you edit, change the name

jobs:
  check-contents:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v5
    
    # Install dependencies
    - name: Set up Python 
      uses: actions/setup-python@v5
      with:
        python-version: 3.12
    
    - name: Install Utils
      run: |
        pip install git+https://github.com/compsys-progtools/courseutils@main
    - name: Get badge requirements
      run: |
        # prepare badge lines
        pretitle="prepare-"$(cspt getbadgedate --prepare)
        cspt getassignment --type prepare | gh issue create --title $pretitle --label prepare --body-file -
        # review badge lines
        rtitle="review-"$(cspt getbadgedate --review)
        cspt getassignment --type review | gh issue create --title $rtitle --label review --body-file -
        # practice badge lines
        pratitle="practice-"$(cspt getbadgedate --practice)
        cspt getassignment --type practice | gh issue create --title $pratitle --label practice --body-file -
      env:
        GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
#  edit the run step above for the level(s) you want. 
#  You should keep the prepare, because they are required for experience badges 
#     You may choose to get only the review or only the practice (and change this any time)
nano .github/workflows/label_badges.yml

then commit directly to main

git add .
git commit -m 'turn on schedule'
[main 3f55616] turn on schedule
 1 file changed, 2 insertions(+), 2 deletions(-)

and push

git push
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 16 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 460 bytes | 460.00 KiB/s, done.
Total 5 (delta 3), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
To https://github.com/compsys-progtools/fall25-kwl-brownsarahm.git
   4714a02..3f55616  main -> main

Variables in Bash

The basic syntas is:

MYVAR=my_val

where:

so for example:

NAME='sarah'

A common mistake is to put a space around the = sign, this is actually considered good style in many other languages.

NAME = 'sarah'
-bash: NAME: command not found

In bash, however, this creates an error. When there is a space after NAME, bash tried to interpet NAME as a bash command, but then it does not find it, so it gives an error.

Removing the space works again:

NAME='sarah'

we can use variables with a $ before the variable name.

echo $NAME
sarah

Environment Variables

Environment variables are global.

A common one is the PATH. This variable is where your computer looks for programs to run when you call commands.

echo $PATH
/Users/brownsarahm/miniforge3/condabin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Frameworks/Python.framework/Versions/3.13/bin

Another is PS1, this sets your prompt

echo $PS1
\u@\W \$

This one sets my prompt to look like: username@last_part_of_path $

so if my path is /Users/brownsarahm/Documents/inclass my prompt will read brownsarahm@inclass $

You can store environment variables to be set each time you start a terminal in your profile.

Variables are path independent

We can, however use the variable at different working directories. So if we move

cd ../gh-inclass-fa25-brownsarahm/

and call it again

echo $NAME
sarah

still works !

The $ is essential syntax for recalling variables in bash. If we forget it, it treats it as a literal

echo NAME
NAME

so we get the variable name out instead of the variable value

GH Actions as an example of scripts

Check out the github action marketplace to see other actions that are available and try to get a casual level of understanding of the types of things that people use actions for.

Bash Loops

We can also make loops like

for loopvar in list
do
# loop body
echo $loopvar
done

So, for example:

for name in Sarah Karter Kevin
> do
> echo $name
> done
Sarah
Karter
Kevin

Notes:

When we get the command back with the up arrow key, it puts it all on one line, because it was one command. The ; (semicolon) separates the “lines”

for name in Sarah Karter Kevin Jack Ayman; do echo $name; done
Sarah
Karter
Kevin
Jack
Ayman

Nesting commands

We can run a command to generate the list by putting it inside $() to run that command first. Think kind of like PEMDAS and the $ in bash is for variables.

for file in $(ls)
> do
> echo $file
> done
README.md

the $() tells bash to run that command first and then hold its output as a variable for use elsewhere

We can modify what is in the $():

for file in $(ls -a); do echo $file; done
.
..
.git
.github
.secret
README.md

Conditionals in bash

We can also do conditional statements

if test -f docs\
> then
> echo "file"
> fi
-bash: syntax error near unexpected token `fi'

I made a typo, pressing \ instead of . To figure out what happened and understand that error, I used the up arrow key to get back the command:

if test -f docsthen; echo "file"; fi

the \ is interpetted as nothing so then without the then keyword the fi is a syntax error

I tried to fix it by adding a ; after docs

if test -f docs; then; echo "file"; fi
-bash: syntax error near unexpected token `;'

this was still an error, so I retyped the whole thing:

if test -f docs
> then
> echo "file"
> fi

and used the up arrow here

if test -f docs; then echo "file"; fi

I learned that the then keyword can be on its own line visually, but it is not a full line that can be separated with ;

To recall, the correct if is

if test -f docs
> then
> echo "file"
> fi

the key parts of this:

This outputs nothing because docs doesn’t exist, but we can switch branches:

git checkout organization
Previous HEAD position was 99f86bf create a readme closes #1
Switched to branch 'organization'
Your branch is up to date with 'origin/organization'.
if test -f docs; then echo "file"; fi

Now it outputs nothing because docs is a directory not a file.

If we switch it, we get output:

if test -f API.md; then echo "file"; fi
file

Script files

We can put bash commands into a file to make them a script

nano filecheck.sh
filecheck.sh
echo "hello world"

and run it with bash <filename>

bash filecheck.sh
hello world

Prepare for Next Class

  1. In fractionalbinary.md use 8 bits to represent the following numbers by using 4 bits as usual (8,4,2,1) and the other 4 bits are 1/2, 1/4, 1/8, 1/16th:

  1. Add to your file some notes about the limitations of representing non integer values this way. How much would using more bits help with, what limitations are not resolved by adding more bits. For example, how could you represent .1?

Badges

Review
Practice
  1. Review the notes from today

  2. Update your KWL Chart learned column with what you’ve learned

  3. write a bash script to make it so that cating the the files in your gh_inclass repo does not make the prompt move

Experience Report Evidence

Questions After Today’s Class